diff --git a/.gitignore b/.gitignore index 3193fc0..da336f2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /**/spa/**/style.css docs/md-build +docs/tmp # Created by https://www.toptal.com/developers/gitignore/api/python,solidity,visualstudiocode,react # Edit at https://www.toptal.com/developers/gitignore?templates=python,solidity,visualstudiocode,react diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bfddaf5..d2292da 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,11 +28,11 @@ New addition to the codebase must be fully documented. - JavaScript portions of the code should be annotated using JSDoc style docstrings. -- Solidity portions of the code should be fully annotated using [NatSpec] and [Solidity Domain for Sphinx]. +- Solidity portions of the code should be fully annotated using [NatSpec]. -Documentation is generated using [solidity-docgen] and rendered via [mkdocs]. -[solidity-docgen] parses NatSpec and outputs `.md` files inside `docs/md-build` according -to an Handlebars template located at `docs/solidity-docgen-templates/contract.hbs`. +Documentation is generated using [py-solidity-docgen] and rendered via [mkdocs]. +[py-solidity-docgen] parses NatSpec and outputs `.md` files inside `docs/md-build` according +to a pre-specified Jinja2 template. **NOTE:** Each `.sol` file should contain only one `Interface` or `Contract`. @@ -50,7 +50,7 @@ yarn docs:serve ### mkdocs -To install [mkdocs] Python must be installed in the system. +To install [mkdocs] and [py-solidity-docgen] Python must be installed in the system. ``` pip install docs/requirements.in @@ -63,5 +63,5 @@ pip install docs/requirements.in [Solidity Styleguide]: https://solidity.readthedocs.io/en/v0.7.0/style-guide.html [NatSpec]: https://solidity.readthedocs.io/en/v0.7.0/style-guide.html#natspec [Write the Docs!]: docs/source/write_the_docs.rst -[solidity-docgen]: https://github.com/OpenZeppelin/solidity-docgen +[py-solidity-docgen]: https://github.com/b-u-i-d-l/py-solidity-docgen [mkdocs]: https://www.mkdocs.org/ diff --git a/contracts/stableCoin/farming/IUnifiedStableFarming.sol b/contracts/stableCoin/farming/IUnifiedStableFarming.sol index 710db11..617738f 100644 --- a/contracts/stableCoin/farming/IUnifiedStableFarming.sol +++ b/contracts/stableCoin/farming/IUnifiedStableFarming.sol @@ -2,6 +2,10 @@ pragma solidity >=0.7.0 <0.8.0; +/** + * @title UnifiedStableFarming + * @dev Arbitrage helper + */ interface IUnifiedStableFarming { function percentage() external view returns (uint256[] memory); @@ -51,3 +55,73 @@ interface IUnifiedStableFarming { uint256[] calldata stableCoinAmounts ) external; } + +interface IStableCoin { + function allowedPairs() external view returns (address[] memory); + + function fromTokenToStable(address tokenAddress, uint256 amount) + external + view + returns (uint256); + + function mint( + uint256 pairIndex, + uint256 amount0, + uint256 amount1, + uint256 amount0Min, + uint256 amount1Min + ) external returns (uint256); + + function burn( + uint256 pairIndex, + uint256 pairAmount, + uint256 amount0, + uint256 amount1 + ) external returns (uint256, uint256); +} + +interface IUniswapV2Pair { + function token0() external view returns (address); + + function token1() external view returns (address); +} + +interface IUniswapV2Router02 { + function WETH() external pure returns (address); + + function getAmountsOut(uint256 amountIn, address[] calldata path) + external + view + returns (uint256[] memory amounts); + + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline + ) external returns (uint256[] memory amounts); + + function swapExactETHForTokens( + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline + ) external payable returns (uint256[] memory amounts); +} + +interface IERC20 { + function balanceOf(address account) external view returns (uint256); + + function transfer(address recipient, uint256 amount) external returns (bool); + + function allowance(address owner, address spender) external view returns (uint256); + + function approve(address spender, uint256 amount) external returns (bool); + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); +} diff --git a/contracts/stableCoin/farming/UnifiedStableFarming.sol b/contracts/stableCoin/farming/UnifiedStableFarming.sol index 66e92bc..5c005df 100644 --- a/contracts/stableCoin/farming/UnifiedStableFarming.sol +++ b/contracts/stableCoin/farming/UnifiedStableFarming.sol @@ -1,20 +1,18 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.8.0; +pragma solidity ^0.7.0; import "./IUnifiedStableFarming.sol"; -import "../standalone/IStableCoin.sol"; -import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; -import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; contract UnifiedStableFarming is IUnifiedStableFarming { - address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; + address + private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; address private WETH_ADDRESS; uint256[] private _percentage; - constructor(uint256[] memory percentage) public { + constructor(uint256[] memory percentage) { WETH_ADDRESS = IUniswapV2Router02(UNISWAP_V2_ROUTER).WETH(); assert(percentage.length == 2); _percentage = percentage; @@ -42,7 +40,12 @@ contract UnifiedStableFarming is IUnifiedStableFarming { uint256 realTokenValue = tokenAddress == WETH_ADDRESS ? msg.value : tokenValue; _swap(tokenAddress, stableCoinAddress, realTokenValue, address(this)); // Swap stablecoin for $uSD - IStableCoin(stableCoinAddress).burn(pairIndex, pairAmount, amountAMin, amountBMin); + IStableCoin(stableCoinAddress).burn( + pairIndex, + pairAmount, + amountAMin, + amountBMin + ); (address tokenA, address tokenB, ) = _getPairData(stableCoinAddress, pairIndex); // Send the tokens back to their owner _flushToSender(tokenA, tokenB, stableCoinAddress, address(0)); @@ -77,7 +80,13 @@ contract UnifiedStableFarming is IUnifiedStableFarming { amountB ); // Mint $uSD - IStableCoin(stableCoinAddress).mint(pairIndex, amountA, amountB, amountAMin, amountBMin); + IStableCoin(stableCoinAddress).mint( + pairIndex, + amountA, + amountB, + amountAMin, + amountBMin + ); // For each of the chosen output pair swap $uSD to obtain the desired amount of stablecoin for (uint256 i = 0; i < tokenIndices.length; i++) { _swap( @@ -204,7 +213,7 @@ contract UnifiedStableFarming is IUnifiedStableFarming { path[1] = tokenOut; if (path[0] == WETH_ADDRESS) { return - uniswapV2Router.swapExactETHForTokens{value: amountIn}( + uniswapV2Router.swapExactETHForTokens{ value: amountIn }( uniswapV2Router.getAmountsOut(amountIn, path)[1], path, receiver, diff --git a/contracts/stableCoin/microservices/IMVDFunctionalitiesManager.sol b/contracts/stableCoin/microservices/IMVDFunctionalitiesManager.sol deleted file mode 100644 index 72d2e2d..0000000 --- a/contracts/stableCoin/microservices/IMVDFunctionalitiesManager.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.6.0; - -interface IMVDFunctionalitiesManager { - function isAuthorizedFunctionality(address functionality) external view returns (bool); -} diff --git a/contracts/stableCoin/microservices/IMVDProxy.sol b/contracts/stableCoin/microservices/IMVDProxy.sol deleted file mode 100644 index 917c2b2..0000000 --- a/contracts/stableCoin/microservices/IMVDProxy.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.8.0; - -interface IMVDProxy { - function getToken() external view returns (address); - - function getStateHolderAddress() external view returns (address); - - function getMVDFunctionalitiesManagerAddress() external view returns (address); - - function transfer( - address receiver, - uint256 value, - address token - ) external; - - function flushToWallet( - address tokenAddress, - bool is721, - uint256 tokenId - ) external; -} diff --git a/contracts/stableCoin/microservices/IStateHolder.sol b/contracts/stableCoin/microservices/IStateHolder.sol deleted file mode 100644 index c2ade9c..0000000 --- a/contracts/stableCoin/microservices/IStateHolder.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.8.0; - -interface IStateHolder { - function clear(string calldata varName) - external - returns (string memory oldDataType, bytes memory oldVal); - - function setBool(string calldata varName, bool val) external returns (bool); - - function getBool(string calldata varName) external view returns (bool); -} diff --git a/contracts/stableCoin/microservices/MintNewVotingTokensForStableCoinFunctionality.sol b/contracts/stableCoin/microservices/MintNewVotingTokensForStableCoinFunctionality.sol index 471d0a0..20504a0 100644 --- a/contracts/stableCoin/microservices/MintNewVotingTokensForStableCoinFunctionality.sol +++ b/contracts/stableCoin/microservices/MintNewVotingTokensForStableCoinFunctionality.sol @@ -1,34 +1,19 @@ -/* Discussion: - * https://github.com/b-u-i-d-l/unifi - */ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.8.0; /* Description: - * When a stablecoin loses value, the Uniswap Tier pools rebalance to an uneven disparity (≠ 50/50). - * If the stablecoin totally fails, the other stablecoins effectively pump in correlation. + * When a stablecoin loses value, the Uniswap Tier pools rebalance to an uneven disparity (≠ 50/50). If the stablecoin totally fails, the other stablecoins effectively pump in correlation. * - * DFO Debit resolves this issue on-chain by rebalancing uSD, creating debt which the UniFi DFO - * then pays off by minting UniFi. Let’s look at how this plays out, step by step: + * DFO Debit resolves this issue on-chain by rebalancing uSD, creating debt which the UniFi DFO then pays off by minting UniFi. Let’s look at how this plays out, step by step: * * 1 - A stablecoin collateralized by uSD loses value or fails altogether. * - * 2 - $UniFi holders vote to remove the tiers containing the failed stablecoin from the whitelist. - * The uSD supply becomes grater than the supply of the collateralized pooled stablecoins. + * 2 - $UniFi holders vote to remove the tiers containing the failed stablecoin from the whitelist.The uSD supply becomes grater than the supply of the collateralized pooled stablecoins. * - * 3 - To restore 1:1 equilibrium, anyone holding uSD can burn it to receive new UniFi, minted at a - * 50% discount of the uSD/UniFi Uniswap pool mid-price ratio. + * 3 - To restore 1:1 equilibrium, anyone holding uSD can burn it to receive new UniFi, minted at a 50% discount of the uSD/UniFi Uniswap pool mid-price ratio. * - * The goal of $UniFi holders, which aligns with their self-interest, is to ensure uSD's security. - * Thus there is an economic disincentive to whitelist insecure stablecoins. + * The goal of $UniFi holders, which aligns with their self-interest, is to ensure uSD’s security. Thus there is an economic disincentive to whitelist insecure stablecoins. */ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.8.0; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import "./IMVDFunctionalitiesManager.sol"; -import "./IMVDProxy.sol"; -import "./IStateHolder.sol"; /** * @title Mint Voting Tokens ($unifi) by burning Stable Coin ($uSD) @@ -36,7 +21,9 @@ import "./IStateHolder.sol"; */ contract MintNewVotingTokensForStableCoinFunctionality { function onStart(address, address) public { - IStateHolder stateHolder = IStateHolder(IMVDProxy(msg.sender).getStateHolderAddress()); + IStateHolder stateHolder = IStateHolder( + IMVDProxy(msg.sender).getStateHolderAddress() + ); address stablecoinauthorized = 0x44086035439E676c02D411880FcCb9837CE37c57; stateHolder.setBool( _toStateHolderKey("stablecoin.authorized", _toString(stablecoinauthorized)), @@ -45,7 +32,9 @@ contract MintNewVotingTokensForStableCoinFunctionality { } function onStop(address) public { - IStateHolder stateHolder = IStateHolder(IMVDProxy(msg.sender).getStateHolderAddress()); + IStateHolder stateHolder = IStateHolder( + IMVDProxy(msg.sender).getStateHolderAddress() + ); address stablecoinauthorized = 0x44086035439E676c02D411880FcCb9837CE37c57; stateHolder.clear( _toStateHolderKey("stablecoin.authorized", _toString(stablecoinauthorized)) @@ -105,8 +94,53 @@ contract MintNewVotingTokensForStableCoinFunctionality { function _toLowerCase(string memory str) private pure returns (string memory) { bytes memory bStr = bytes(str); for (uint256 i = 0; i < bStr.length; i++) { - bStr[i] = bStr[i] >= 0x41 && bStr[i] <= 0x5A ? bytes1(uint8(bStr[i]) + 0x20) : bStr[i]; + bStr[i] = bStr[i] >= 0x41 && bStr[i] <= 0x5A + ? bytes1(uint8(bStr[i]) + 0x20) + : bStr[i]; } return string(bStr); } } + +interface IMVDProxy { + function getToken() external view returns (address); + + function getStateHolderAddress() external view returns (address); + + function getMVDFunctionalitiesManagerAddress() external view returns (address); + + function transfer( + address receiver, + uint256 value, + address token + ) external; + + function flushToWallet( + address tokenAddress, + bool is721, + uint256 tokenId + ) external; +} + +interface IMVDFunctionalitiesManager { + function isAuthorizedFunctionality(address functionality) + external + view + returns (bool); +} + +interface IStateHolder { + function clear(string calldata varName) + external + returns (string memory oldDataType, bytes memory oldVal); + + function setBool(string calldata varName, bool val) external returns (bool); + + function getBool(string calldata varName) external view returns (bool); +} + +interface IERC20 { + function mint(uint256 amount) external; + + function balanceOf(address account) external view returns (uint256); +} diff --git a/contracts/stableCoin/standalone/Address.sol b/contracts/stableCoin/standalone/Address.sol new file mode 100644 index 0000000..774e56c --- /dev/null +++ b/contracts/stableCoin/standalone/Address.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies in extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return _functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + return _functionCallWithValue(target, data, value, errorMessage); + } + + function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} \ No newline at end of file diff --git a/contracts/stableCoin/standalone/Context.sol b/contracts/stableCoin/standalone/Context.sol new file mode 100644 index 0000000..df4d6e1 --- /dev/null +++ b/contracts/stableCoin/standalone/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} \ No newline at end of file diff --git a/contracts/stableCoin/standalone/ERC20.sol b/contracts/stableCoin/standalone/ERC20.sol new file mode 100644 index 0000000..6d9fa02 --- /dev/null +++ b/contracts/stableCoin/standalone/ERC20.sol @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +import "./Context.sol"; +import "./IERC20.sol"; +import "./SafeMath.sol"; +import "./Address.sol"; +import "./IStableCoin.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +abstract contract ERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + function init(string memory name, string memory symbol) internal { + require( + keccak256(bytes(_symbol)) == keccak256(""), + "Init already Called!" + ); + _name = name; + _symbol = symbol; + _decimals = 18; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public override view returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public override view returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) + public + virtual + override + returns (bool) + { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) + public + virtual + override + view + returns (uint256) + { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) + public + virtual + override + returns (bool) + { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + _msgSender(), + _allowances[sender][_msgSender()].sub( + amount, + "ERC20: transfer amount exceeds allowance" + ) + ); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].add(addedValue) + ); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + _approve( + _msgSender(), + spender, + _allowances[_msgSender()][spender].sub( + subtractedValue, + "ERC20: decreased allowance below zero" + ) + ); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer( + address sender, + address recipient, + uint256 amount + ) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub( + amount, + "ERC20: burn amount exceeds balance" + ); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Sets {decimals} to a value other than the default one of 18. + * + * WARNING: This function should only be called from the constructor. Most + * applications that interact with token contracts will not expect + * {decimals} to ever change, and may work incorrectly if it does. + */ + function _setupDecimals(uint8 decimals_) internal { + _decimals = decimals_; + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} \ No newline at end of file diff --git a/contracts/stableCoin/standalone/IDoubleProxy.sol b/contracts/stableCoin/standalone/IDoubleProxy.sol deleted file mode 100644 index 5b6c101..0000000 --- a/contracts/stableCoin/standalone/IDoubleProxy.sol +++ /dev/null @@ -1,6 +0,0 @@ -pragma solidity ^0.6.0; - -// DOCUMENT -interface IDoubleProxy { - function proxy() external view returns (address); -} diff --git a/contracts/stableCoin/standalone/IERC20.sol b/contracts/stableCoin/standalone/IERC20.sol new file mode 100644 index 0000000..c6eb6d3 --- /dev/null +++ b/contracts/stableCoin/standalone/IERC20.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} \ No newline at end of file diff --git a/contracts/stableCoin/standalone/IMVDFunctionalitiesManager.sol b/contracts/stableCoin/standalone/IMVDFunctionalitiesManager.sol deleted file mode 100644 index 9cba846..0000000 --- a/contracts/stableCoin/standalone/IMVDFunctionalitiesManager.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.8.0; - -// DOCUMENT -interface IMVDFunctionalitiesManager { - function isAuthorizedFunctionality(address functionality) external view returns (bool); -} diff --git a/contracts/stableCoin/standalone/IMVDProxy.sol b/contracts/stableCoin/standalone/IMVDProxy.sol deleted file mode 100644 index be23c23..0000000 --- a/contracts/stableCoin/standalone/IMVDProxy.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.8.0; - -// DOCUMENT -interface IMVDProxy { - function getToken() external view returns (address); - - function getMVDFunctionalitiesManagerAddress() external view returns (address); - - function getMVDWalletAddress() external view returns (address); - - function getStateHolderAddress() external view returns (address); - - function submit(string calldata codeName, bytes calldata data) - external - payable - returns (bytes memory returnData); -} diff --git a/contracts/stableCoin/standalone/IStableCoin.sol b/contracts/stableCoin/standalone/IStableCoin.sol index 53a53ef..c14b4d8 100644 --- a/contracts/stableCoin/standalone/IStableCoin.sol +++ b/contracts/stableCoin/standalone/IStableCoin.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.8.0; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +pragma solidity ^0.7.0; +import "./IERC20.sol"; /** * @title Interface for the $uSD aka unified Stable Dollar. @@ -13,7 +12,6 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; * rebalancing schemes, $uSD is able reduce an holder exposure to a stable-coin failure. * */ - interface IStableCoin is IERC20 { /** * Initialize the StableCoin. @@ -120,7 +118,7 @@ interface IStableCoin is IERC20 { * @param amountBMin Bounds the extent to which the A/B price can go up before the transaction reverts. * Must be <= amountBDesired * - * @return Amount of freshly minted $uSD token + * @return minted Amount of freshly minted $uSD token */ function mint( uint256 pairIndex, @@ -128,7 +126,7 @@ interface IStableCoin is IERC20 { uint256 amountB, uint256 amountAMin, uint256 amountBMin - ) external returns (uint256); + ) external returns (uint256 minted); /** * Burn logic of the StableCoin. @@ -139,8 +137,8 @@ interface IStableCoin is IERC20 { * @param amountAMin The minimum amount of tokenA that must be received for the transaction not to revert * @param amountBMin The minimum amount of tokenB that must be received for the transaction not to revert * - * @return amountA The amount of tokenA received - * @return amountB The amount of tokenB received + * @return removedA The amount of tokenA received + * @return removedB The amount of tokenB received * */ function burn( @@ -148,7 +146,7 @@ interface IStableCoin is IERC20 { uint256 pairAmount, uint256 amountAMin, uint256 amountBMin - ) external returns (uint256 amountA, uint256 amountB); + ) external returns (uint256 removedA, uint256 removedB); /** * @dev Rebalance by Credit is triggered when the total amount of source tokens' is greater @@ -174,3 +172,87 @@ interface IStableCoin is IERC20 { */ function rebalanceByDebt(uint256 amount) external returns (uint256); } + +interface IDoubleProxy { + function proxy() external view returns (address); +} + +interface IMVDProxy { + function getToken() external view returns (address); + + function getMVDFunctionalitiesManagerAddress() external view returns (address); + + function getMVDWalletAddress() external view returns (address); + + function getStateHolderAddress() external view returns (address); + + function submit(string calldata codeName, bytes calldata data) + external + payable + returns (bytes memory returnData); +} + +interface IMVDFunctionalitiesManager { + function isAuthorizedFunctionality(address functionality) external view returns (bool); +} + +interface IStateHolder { + function getBool(string calldata varName) external view returns (bool); + + function getUint256(string calldata varName) external view returns (uint256); +} + +interface IUniswapV2Router02 { + function getAmountsOut(uint256 amountIn, address[] calldata path) + external + view + returns (uint256[] memory amounts); + + function removeLiquidity( + address tokenA, + address tokenB, + uint256 liquidity, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) external returns (uint256 amountA, uint256 amountB); + + function addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) + external + returns ( + uint256 amountA, + uint256 amountB, + uint256 liquidity + ); +} + +interface IUniswapV2Pair { + function decimals() external pure returns (uint8); + + function totalSupply() external view returns (uint256); + + function token0() external view returns (address); + + function token1() external view returns (address); + + function balanceOf(address account) external view returns (uint256); + + function getReserves() + external + view + returns ( + uint112 reserve0, + uint112 reserve1, + uint32 blockTimestampLast + ); +} diff --git a/contracts/stableCoin/standalone/IStateHolder.sol b/contracts/stableCoin/standalone/IStateHolder.sol deleted file mode 100644 index 6926edf..0000000 --- a/contracts/stableCoin/standalone/IStateHolder.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.7.0 <0.8.0; - -// DOCUMENT -interface IStateHolder { - function getBool(string calldata varName) external view returns (bool); - - function getUint256(string calldata varName) external view returns (uint256); -} diff --git a/contracts/stableCoin/standalone/SafeMath.sol b/contracts/stableCoin/standalone/SafeMath.sol new file mode 100644 index 0000000..4f9c084 --- /dev/null +++ b/contracts/stableCoin/standalone/SafeMath.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction overflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} \ No newline at end of file diff --git a/contracts/stableCoin/standalone/StableCoin.sol b/contracts/stableCoin/standalone/StableCoin.sol index bdd0fab..e787afc 100644 --- a/contracts/stableCoin/standalone/StableCoin.sol +++ b/contracts/stableCoin/standalone/StableCoin.sol @@ -1,15 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.7.0 <0.8.0; +pragma solidity ^0.7.0; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; -import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; +import "./ERC20.sol"; import "./IStableCoin.sol"; -import "./IMVDFunctionalitiesManager.sol"; -import "./IMVDProxy.sol"; -import "./IDoubleProxy.sol"; -import "./IStateHolder.sol"; /** * @title StableCoin @@ -21,7 +15,8 @@ contract StableCoin is ERC20, IStableCoin { // | ----- ATTRIBUTES ----- | // |------------------------------------------------------------------------------------------| - address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; + address + private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; address private _doubleProxy; @@ -50,7 +45,7 @@ contract StableCoin is ERC20, IStableCoin { uint256[] memory rebalanceRewardMultiplier, uint256[] memory timeWindows, uint256[] memory mintables - ) public { + ) { if (doubleProxy == address(0)) { return; } @@ -103,8 +98,13 @@ contract StableCoin is ERC20, IStableCoin { * @inheritdoc IStableCoin */ function availableToMint() public override view returns (uint256) { - uint256 mintable = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; - if (_timeWindows.length > 0 && block.number < _timeWindows[_timeWindows.length - 1]) { + + uint256 mintable + = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + if ( + _timeWindows.length > 0 && + block.number < _timeWindows[_timeWindows.length - 1] + ) { for (uint256 i = 0; i < _timeWindows.length; i++) { if (block.number < _timeWindows[i]) { mintable = _mintables[i]; @@ -147,7 +147,12 @@ contract StableCoin is ERC20, IStableCoin { /** * @inheritdoc IStableCoin */ - function tierData() public override view returns (uint256[] memory, uint256[] memory) { + function tierData() + public + override + view + returns (uint256[] memory, uint256[] memory) + { return (_timeWindows, _mintables); } @@ -158,7 +163,11 @@ contract StableCoin is ERC20, IStableCoin { /** * @inheritdoc IStableCoin */ - function setAllowedPairs(address[] memory newAllowedPairs) public override _byCommunity { + function setAllowedPairs(address[] memory newAllowedPairs) + public + override + _byCommunity + { _allowedPairs = newAllowedPairs; } @@ -226,8 +235,12 @@ contract StableCoin is ERC20, IStableCoin { ) public override _forAllowedPair(pairIndex) returns (uint256 minted) { // NOTE: Use DFO protocol to check for authorization require( - IStateHolder(IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).getStateHolderAddress()) - .getBool(_toStateHolderKey("stablecoin.authorized", _toString(address(this)))), + IStateHolder( + IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).getStateHolderAddress() + ) + .getBool( + _toStateHolderKey("stablecoin.authorized", _toString(address(this))) + ), "Unauthorized action!" ); (address tokenA, address tokenB, ) = _getPairData(pairIndex); @@ -241,8 +254,13 @@ contract StableCoin is ERC20, IStableCoin { amountAMin, amountBMin ); - minted = fromTokenToStable(tokenA, firstAmount) + fromTokenToStable(tokenB, secondAmount); - require(minted <= availableToMint(), "Minting amount is greater than availability!"); + minted = + fromTokenToStable(tokenA, firstAmount) + + fromTokenToStable(tokenB, secondAmount); + require( + minted <= availableToMint(), + "Minting amount is greater than availability!" + ); _mint(msg.sender, minted); } @@ -255,7 +273,12 @@ contract StableCoin is ERC20, IStableCoin { uint256 pairAmount, uint256 amountAMin, uint256 amountBMin - ) public override _forAllowedPair(pairIndex) returns (uint256 removedA, uint256 removedB) { + ) + public + override + _forAllowedPair(pairIndex) + returns (uint256 removedA, uint256 removedB) + { (address tokenA, address tokenB, address pairAddress) = _getPairData(pairIndex); _checkAllowance(pairAddress, pairAmount); // Remove pooled stablecoins @@ -292,7 +315,8 @@ contract StableCoin is ERC20, IStableCoin { block.number >= _lastRedeemBlock + IStateHolder( - IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).getStateHolderAddress() + IMVDProxy(IDoubleProxy(_doubleProxy).proxy()) + .getStateHolderAddress() ) .getUint256("stablecoin.rebalancebycredit.block.interval"), "Unauthorized action!" @@ -311,7 +335,9 @@ contract StableCoin is ERC20, IStableCoin { IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).getMVDWalletAddress(), block.timestamp + 1000 ); - redeemed = fromTokenToStable(tokenA, removed0) + fromTokenToStable(tokenB, removed1); + redeemed = + fromTokenToStable(tokenA, removed0) + + fromTokenToStable(tokenB, removed1); require(redeemed <= credit, "Cannot redeem given pair amount"); } @@ -325,7 +351,12 @@ contract StableCoin is ERC20, IStableCoin { _burn(msg.sender, amount); IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).submit( "mintNewVotingTokensForStableCoin", - abi.encode(address(0), 0, reward = calculateRebalanceByDebtReward(amount), msg.sender) + abi.encode( + address(0), + 0, + reward = calculateRebalanceByDebtReward(amount), + msg.sender + ) ); } @@ -337,7 +368,8 @@ contract StableCoin is ERC20, IStableCoin { modifier _byCommunity() { require( IMVDFunctionalitiesManager( - IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).getMVDFunctionalitiesManagerAddress() + IMVDProxy(IDoubleProxy(_doubleProxy).proxy()) + .getMVDFunctionalitiesManagerAddress() ) .isAuthorizedFunctionality(msg.sender), "Unauthorized Action!" @@ -375,7 +407,9 @@ contract StableCoin is ERC20, IStableCoin { /** * // DOCUMENT */ - function _transferTokensAndCheckAllowance(address tokenAddress, uint256 value) private { + function _transferTokensAndCheckAllowance(address tokenAddress, uint256 value) + private + { IERC20(tokenAddress).transferFrom(msg.sender, address(this), value); _checkAllowance(tokenAddress, value); } @@ -426,7 +460,8 @@ contract StableCoin is ERC20, IStableCoin { uint256 liquidity ) { - (amountA, amountB, liquidity) = IUniswapV2Router02(UNISWAP_V2_ROUTER).addLiquidity( + (amountA, amountB, liquidity) = IUniswapV2Router02(UNISWAP_V2_ROUTER) + .addLiquidity( tokenA, tokenB, amountADesired, @@ -447,7 +482,11 @@ contract StableCoin is ERC20, IStableCoin { /** * // DOCUMENT */ - function _getPairAmount(uint256 i) private view returns (uint256 amount0, uint256 amount1) { + function _getPairAmount(uint256 i) + private + view + returns (uint256 amount0, uint256 amount1) + { (address token0, address token1, address pairAddress) = _getPairData(i); IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); uint256 pairAmount = pair.balanceOf(address(this)); @@ -491,7 +530,9 @@ contract StableCoin is ERC20, IStableCoin { function _toLowerCase(string memory str) private pure returns (string memory) { bytes memory bStr = bytes(str); for (uint256 i = 0; i < bStr.length; i++) { - bStr[i] = bStr[i] >= 0x41 && bStr[i] <= 0x5A ? bytes1(uint8(bStr[i]) + 0x20) : bStr[i]; + bStr[i] = bStr[i] >= 0x41 && bStr[i] <= 0x5A + ? bytes1(uint8(bStr[i]) + 0x20) + : bStr[i]; } return string(bStr); } diff --git a/docs/to_lowercase.sh b/docs/to_lowercase.sh deleted file mode 100755 index 80ec06f..0000000 --- a/docs/to_lowercase.sh +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/bash - -sed -i -E 's/(\(#.*)/\L\1\E/g' md-build/stableCoin/**/*.md