diff --git a/contracts/NewBancorPool.sol b/contracts/NewBancorPool.sol index 935f2e7..daee5df 100644 --- a/contracts/NewBancorPool.sol +++ b/contracts/NewBancorPool.sol @@ -26,16 +26,14 @@ import "./storage/BnStorage.sol"; import "./storage/BnConstants.sol"; -contract NewBancorPool is BnStorage, BnConstants, Managed { +contract NewBancorPool2 is BnStorage, BnConstants, Managed { ContractRegistry public contractRegistry; - //ContractRegistryClient public contractRegistryClient; SmartToken public smartToken; BancorConverter public bancorConverter; BancorConverterFactory public bancorConverterFactory; BancorConverterRegistry public bancorConverterRegistry; - BancorConverterRegistryData public bancorConverterRegistryData; BancorFormula public bancorFormula; @@ -51,13 +49,8 @@ contract NewBancorPool is BnStorage, BnConstants, Managed { address bancorConverterAddr; - address BANCOR_CONVERTER_REGISTRY_DATA; - address BANCOR_FORMULA; // ContractAddress of BancorFormula.sol - - constructor( address _contractRegistry, - //address _contractRegistryClient, address _BNTtokenAddr, address _ERC20tokenAddr, address _cDAItokenAddr, @@ -65,14 +58,12 @@ contract NewBancorPool is BnStorage, BnConstants, Managed { address _bancorConverter, //address _bancorConverterFactory, address _bancorConverterRegistry, - address _bancorConverterRegistryData, address _bancorFormula ) public { // Step #1: Initial Setup contractRegistry = ContractRegistry(_contractRegistry); - //contractRegistryClient = ContractRegistryClient(_contractRegistryClient); contractRegistryAddr = _contractRegistry; @@ -84,9 +75,6 @@ contract NewBancorPool is BnStorage, BnConstants, Managed { bancorConverterAddr = _bancorConverter; - BANCOR_CONVERTER_REGISTRY_DATA = _bancorConverterRegistryData; - BANCOR_FORMULA = _bancorFormula; - token = IERC20Token(ERC20tokenAddr); // Step #2: Smart Relay Token Deployment @@ -113,24 +101,6 @@ contract NewBancorPool is BnStorage, BnConstants, Managed { return bancorNetwork; } - // function testFuncCallBancorConverterFactoryContractAddr() public view returns (IBancorConverterFactory) { - // address bancorConverterFactory; - // //IBancorConverterFactory bancorConverterFactory = IBancorConverterFactory(addressOf(BANCOR_CONVERTER_FACTORY)); - // bancorConverterFactory = contractRegistry.addressOf('BancorConverterFactory'); - // return bancorConverterFactory; - // } - - function testFuncCallBancorConverterUpgraderContractAddr() public view returns (address _bancorConverterUpgrader) { - address bancorConverterUpgrader; - bancorConverterUpgrader = contractRegistry.addressOf('BancorConverterUpgrader'); - return bancorConverterUpgrader; - } - - function _addConverter() public { - bancorConverterRegistry.addConverter(IBancorConverter(bancorConverterAddr)); - } - - /*** @@ -157,28 +127,25 @@ contract NewBancorPool is BnStorage, BnConstants, Managed { smartToken.transfer(receiverAddr, amountOfSmartToken); // Step #3: Converter Deployment - //uint index = 0; + uint index = 0; uint32 reserveRatio = 10; // The case of this, I specify 10% as percentage of ratio. (After I need to divide by 100) - //uint32 _conversionFee = 1000; // Fee: 1,000 (0.1%) - - addConnector(IERC20Token(ERC20tokenAddr), reserveRatio, true); - //bancorConverter.addConnector(IERC20Token(ERC20tokenAddr), reserveRatio, true); - //bancorConverter.setConversionFee(_conversionFee); + uint32 _conversionFee = 1000; // Fee: 1,000 (0.1%) + bancorConverter.addConnector(IERC20Token(ERC20tokenAddr), reserveRatio, true); + bancorConverter.setConversionFee(_conversionFee); // Step #4: Funding & Initial Supply uint256 fundedAmount = 100; - fund(fundedAmount); - //bancorConverter.fund(fundedAmount); + bancorConverter.fund(fundedAmount); // Step #5: Activation // Step #6: Multisig Ownership address _converterAddress; // @notice - This variable is for receiving return value of createConverter() below uint32 _maxConversionFee = 1; - // _converterAddress = bancorConverterFactory.createConverter(smartToken, - // contractRegistry, - // _maxConversionFee, - // token, - // reserveRatio); + _converterAddress = bancorConverterFactory.createConverter(smartToken, + contractRegistry, + _maxConversionFee, + token, + reserveRatio); // Step #7: Converters Registry Listing bancorConverterRegistry.addConverter(IBancorConverter(_converterAddress)); @@ -188,204 +155,7 @@ contract NewBancorPool is BnStorage, BnConstants, Managed { /*********************************************************** - * @notice - Internal function from BancorConverter.sol + * @notice - Internal function below ***********************************************************/ - uint32 private constant RATIO_RESOLUTION = 1000000; - uint64 private constant CONVERSION_FEE_RESOLUTION = 1000000; - - /** - * @dev version number - */ - uint16 public version = 25; - - IWhitelist public conversionWhitelist; // whitelist contract with list of addresses that are allowed to use the converter - IERC20Token[] public reserveTokens; // ERC20 standard token addresses (prior version 17, use 'connectorTokens' instead) - - struct Reserve { - uint256 virtualBalance; // reserve virtual balance - uint32 ratio; // reserve ratio, represented in ppm, 1-1000000 - bool isVirtualBalanceEnabled; // true if virtual balance is enabled, false if not - bool isSaleEnabled; // is sale of the reserve token enabled, can be set by the owner - bool isSet; // used to tell if the mapping element is defined - } - mapping (address => Reserve) public reserves; // reserve token addresses -> reserve data (prior version 17, use 'connectors' instead) - - uint32 private totalReserveRatio = 0; // used to efficiently prevent increasing the total reserve ratio above 100% - uint32 public maxConversionFee = 0; // maximum conversion fee for the lifetime of the contract, - // represented in ppm, 0...1000000 (0 = no fee, 100 = 0.01%, 1000000 = 100%) - uint32 public conversionFee = 0; // current conversion fee, represented in ppm, 0...maxConversionFee - bool public conversionsEnabled = true; // deprecated, backward compatibility - - - // event Conversion( - // address indexed _fromToken, - // address indexed _toToken, - // address indexed _trader, - // uint256 _amount, - // uint256 _return, - // int256 _conversionFee - // ); - - event PriceDataUpdate( - address indexed _connectorToken, - uint256 _tokenSupply, - uint256 _connectorBalance, - uint32 _connectorWeight - ); - - event SmartTokenAdded(address indexed _smartToken); - event LiquidityPoolAdded(address indexed _liquidityPool); - event ConvertibleTokenAdded(address indexed _convertibleToken, address indexed _smartToken); - - - // validates reserve ratio - modifier validReserveRatio(uint32 _ratio) { - require(_ratio > 0 && _ratio <= RATIO_RESOLUTION); - _; - } - // allows execution only on a multiple-reserve converter - modifier multipleReservesOnly { - require(reserveTokens.length > 1); - _; - } - - - function addConnector(IERC20Token _token, uint32 _weight, bool /*_enableVirtualBalance*/) public { - addReserve(_token, _weight); - } - - function addReserve(IERC20Token _token, uint32 _ratio) - public - ownerOnly - //inactive - //validAddress(_token) - //notThis(_token) - validReserveRatio(_ratio) - { - //require(_token != token && !reserves[_token].isSet && totalReserveRatio + _ratio <= RATIO_RESOLUTION); // validate input - - reserves[_token].ratio = _ratio; - reserves[_token].isVirtualBalanceEnabled = false; - reserves[_token].virtualBalance = 0; - reserves[_token].isSaleEnabled = true; - reserves[_token].isSet = true; - reserveTokens.push(_token); - totalReserveRatio += _ratio; - } - - - /** - * @dev updates the current conversion fee - * can only be called by the manager - * - * @param _conversionFee new conversion fee, represented in ppm - */ - // event ConversionFeeUpdate(uint32 _prevFee, uint32 _newFee); - - // function setConversionFee(uint32 _conversionFee) - // public - // ownerOrManagerOnly - // { - // require(_conversionFee >= 0 && _conversionFee <= maxConversionFee); - // emit ConversionFeeUpdate(conversionFee, _conversionFee); - // conversionFee = _conversionFee; - // } - - - /** - * @dev buys the token with all reserve tokens using the same percentage - * for example, if the caller increases the supply by 10%, - * then it will cost an amount equal to 10% of each reserve token balance - * note that the function can be called only when conversions are enabled - * - * @param _amount amount to increase the supply by (in the smart token) - */ - function fund(uint256 _amount) - public - multipleReservesOnly - { - uint256 supply = smartToken.totalSupply(); - IBancorFormula formula = IBancorFormula(BANCOR_FORMULA); - - // iterate through the reserve tokens and transfer a percentage equal to the ratio between _amount - // and the total supply in each reserve from the caller to the converter - IERC20Token reserveToken; - uint256 reserveBalance; - uint256 reserveAmount; - for (uint16 i = 0; i < reserveTokens.length; i++) { - reserveToken = reserveTokens[i]; - reserveBalance = reserveToken.balanceOf(this); - reserveAmount = formula.calculateFundCost(supply, reserveBalance, totalReserveRatio, _amount); - - Reserve storage reserve = reserves[reserveToken]; - - // transfer funds from the caller in the reserve token - ensureTransferFrom(reserveToken, msg.sender, this, reserveAmount); - - // dispatch price data update for the smart token/reserve - emit PriceDataUpdate(reserveToken, supply + _amount, reserveBalance + reserveAmount, reserve.ratio); - } - - // issue new funds to the caller in the smart token - smartToken.issue(msg.sender, _amount); - } - - function ensureTransferFrom(IERC20Token _token, address _from, address _to, uint256 _amount) private { - // We must assume that functions `transfer` and `transferFrom` do not return anything, - // because not all tokens abide the requirement of the ERC20 standard to return success or failure. - // This is because in the current compiler version, the calling contract can handle more returned data than expected but not less. - // This may change in the future, so that the calling contract will revert if the size of the data is not exactly what it expects. - uint256 prevBalance = _token.balanceOf(_to); - if (_from == address(this)) - INonStandardERC20(_token).transfer(_to, _amount); - else - INonStandardERC20(_token).transferFrom(_from, _to, _amount); - uint256 postBalance = _token.balanceOf(_to); - require(postBalance > prevBalance); - } - - - - function addConverter() external { - // validate input - //require(isConverterValid(_converter)); - - BancorConverterRegistryData converterRegistryData = BancorConverterRegistryData(BANCOR_CONVERTER_REGISTRY_DATA); - uint reserveTokenCount = connectorTokenCount(); - - // add the smart token - addSmartToken(converterRegistryData, smartTokenAddr); - if (reserveTokenCount > 1) - addLiquidityPool(converterRegistryData, smartTokenAddr); - else - addConvertibleToken(converterRegistryData, smartTokenAddr, smartTokenAddr); - - // add all reserve tokens - for (uint i = 0; i < reserveTokenCount; i++) - addConvertibleToken(converterRegistryData, reserveTokens[i], token); - } - - function connectorTokenCount() public view returns (uint16) { - return reserveTokenCount(); - } - - function reserveTokenCount() public view returns (uint16) { - return uint16(reserveTokens.length); - } - - function addSmartToken(IBancorConverterRegistryData _converterRegistryData, address _smartToken) internal { - _converterRegistryData.addSmartToken(_smartToken); - emit SmartTokenAdded(_smartToken); - } - - function addLiquidityPool(IBancorConverterRegistryData _converterRegistryData, address _liquidityPool) internal { - _converterRegistryData.addLiquidityPool(_liquidityPool); - emit LiquidityPoolAdded(_liquidityPool); - } - - function addConvertibleToken(IBancorConverterRegistryData _converterRegistryData, address _convertibleToken, address _smartToken) internal { - _converterRegistryData.addConvertibleToken(_convertibleToken, _smartToken); - emit ConvertibleTokenAdded(_convertibleToken, _smartToken); - } } diff --git a/contracts/bancor-protocol/converter/BancorConverterRegistry.sol b/contracts/bancor-protocol/converter/BancorConverterRegistry.sol index 49f07dd..cb5cf2c 100755 --- a/contracts/bancor-protocol/converter/BancorConverterRegistry.sol +++ b/contracts/bancor-protocol/converter/BancorConverterRegistry.sol @@ -1,468 +1,468 @@ -pragma solidity 0.4.26; -import '../utility/ContractRegistryClient.sol'; -import './interfaces/IBancorConverterRegistry.sol'; -import './interfaces/IBancorConverterRegistryData.sol'; -import '../token/interfaces/ISmartToken.sol'; -import '../token/interfaces/ISmartTokenController.sol'; - -/** - * @dev The BancorConverterRegistry maintains a list of all active converters in the Bancor Network. - * - * Since converters can be upgraded and thus their address can change, the registry actually keeps smart tokens internally and not the converters themselves. - * The active converter for each smart token can be easily accessed by querying the smart token owner. - * - * The registry exposes 3 differnet lists that can be accessed and iterated, based on the use-case of the caller: - * - Smart tokens - can be used to get all the latest / historical data in the network - * - Liquidity pools - can be used to get all liquidity pools for funding, liquidation etc. - * - Convertible tokens - can be used to get all tokens that can be converted in the network (excluding pool - * tokens), and for each one - all smart tokens that hold it in their reserves - * - * - * The contract fires events whenever one of the primitives is added to or removed from the registry - * - * The contract is upgradable. -*/ -contract BancorConverterRegistry is IBancorConverterRegistry, ContractRegistryClient { - /** - * @dev triggered when a smart token is added to the registry - * - * @param _smartToken smart token - */ - event SmartTokenAdded(address indexed _smartToken); - - /** - * @dev triggered when a smart token is removed from the registry - * - * @param _smartToken smart token - */ - event SmartTokenRemoved(address indexed _smartToken); - - /** - * @dev triggered when a liquidity pool is added to the registry - * - * @param _liquidityPool liquidity pool - */ - event LiquidityPoolAdded(address indexed _liquidityPool); - - /** - * @dev triggered when a liquidity pool is removed from the registry - * - * @param _liquidityPool liquidity pool - */ - event LiquidityPoolRemoved(address indexed _liquidityPool); - - /** - * @dev triggered when a convertible token is added to the registry - * - * @param _convertibleToken convertible token - * @param _smartToken associated smart token - */ - event ConvertibleTokenAdded(address indexed _convertibleToken, address indexed _smartToken); - - /** - * @dev triggered when a convertible token is removed from the registry - * - * @param _convertibleToken convertible token - * @param _smartToken associated smart token - */ - event ConvertibleTokenRemoved(address indexed _convertibleToken, address indexed _smartToken); - - /** - * @dev initializes a new BancorConverterRegistry instance - * - * @param _registry address of a contract registry contract - */ - constructor(IContractRegistry _registry) ContractRegistryClient(_registry) public { - } - - /** - * @dev adds a converter to the registry - * anyone can add a converter to the registry, as long as the converter is active and valid - * note that a liquidity pool converter can only be added if there's no existing pool with the same reserve configuration - * - * @param _converter converter - */ - function addConverter(IBancorConverter _converter) external { - // validate input - require(isConverterValid(_converter)); - - IBancorConverterRegistryData converterRegistryData = IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)); - ISmartToken token = ISmartTokenController(_converter).token(); - uint reserveTokenCount = _converter.connectorTokenCount(); - - // add the smart token - addSmartToken(converterRegistryData, token); - if (reserveTokenCount > 1) - addLiquidityPool(converterRegistryData, token); - else - addConvertibleToken(converterRegistryData, token, token); - - // add all reserve tokens - for (uint i = 0; i < reserveTokenCount; i++) - addConvertibleToken(converterRegistryData, _converter.connectorTokens(i), token); - } - - /** - * @dev removes a converter from the registry - * anyone can remove invalid or inactive converters from the registry - * note that the owner can also remove valid converters - * - * @param _converter converter - */ - function removeConverter(IBancorConverter _converter) external { - // validate input - require(msg.sender == owner || !isConverterValid(_converter)); - - IBancorConverterRegistryData converterRegistryData = IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)); - ISmartToken token = ISmartTokenController(_converter).token(); - uint reserveTokenCount = _converter.connectorTokenCount(); - - // remove the smart token - removeSmartToken(converterRegistryData, token); - if (reserveTokenCount > 1) - removeLiquidityPool(converterRegistryData, token); - else - removeConvertibleToken(converterRegistryData, token, token); - - // remove all reserve tokens - for (uint i = 0; i < reserveTokenCount; i++) - removeConvertibleToken(converterRegistryData, _converter.connectorTokens(i), token); - } - - /** - * @dev returns the number of smart tokens in the registry - * - * @return number of smart tokens - */ - function getSmartTokenCount() external view returns (uint) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getSmartTokenCount(); - } - - /** - * @dev returns the list of smart tokens in the registry - * - * @return list of smart tokens - */ - function getSmartTokens() external view returns (address[]) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getSmartTokens(); - } - - /** - * @dev returns the smart token at a given index - * - * @param _index index - * @return smart token at the given index - */ - function getSmartToken(uint _index) external view returns (address) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getSmartToken(_index); - } - - /** - * @dev checks whether or not a given value is a smart token - * - * @param _value value - * @return true if the given value is a smart token, false if not - */ - function isSmartToken(address _value) external view returns (bool) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isSmartToken(_value); - } - - /** - * @dev returns the number of liquidity pools in the registry - * - * @return number of liquidity pools - */ - function getLiquidityPoolCount() external view returns (uint) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getLiquidityPoolCount(); - } - - /** - * @dev returns the list of liquidity pools in the registry - * - * @return list of liquidity pools - */ - function getLiquidityPools() external view returns (address[]) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getLiquidityPools(); - } - - /** - * @dev returns the liquidity pool at a given index - * - * @param _index index - * @return liquidity pool at the given index - */ - function getLiquidityPool(uint _index) external view returns (address) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getLiquidityPool(_index); - } - - /** - * @dev checks whether or not a given value is a liquidity pool - * - * @param _value value - * @return true if the given value is a liquidity pool, false if not - */ - function isLiquidityPool(address _value) external view returns (bool) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isLiquidityPool(_value); - } - - /** - * @dev returns the number of convertible tokens in the registry - * - * @return number of convertible tokens - */ - function getConvertibleTokenCount() external view returns (uint) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenCount(); - } - - /** - * @dev returns the list of convertible tokens in the registry - * - * @return list of convertible tokens - */ - function getConvertibleTokens() external view returns (address[]) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokens(); - } - - /** - * @dev returns the convertible token at a given index - * - * @param _index index - * @return convertible token at the given index - */ - function getConvertibleToken(uint _index) external view returns (address) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleToken(_index); - } - - /** - * @dev checks whether or not a given value is a convertible token - * - * @param _value value - * @return true if the given value is a convertible token, false if not - */ - function isConvertibleToken(address _value) external view returns (bool) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isConvertibleToken(_value); - } - - /** - * @dev returns the number of smart tokens associated with a given convertible token - * - * @param _convertibleToken convertible token - * @return number of smart tokens associated with the given convertible token - */ - function getConvertibleTokenSmartTokenCount(address _convertibleToken) external view returns (uint) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenSmartTokenCount(_convertibleToken); - } - - /** - * @dev returns the list of smart tokens associated with a given convertible token - * - * @param _convertibleToken convertible token - * @return list of smart tokens associated with the given convertible token - */ - function getConvertibleTokenSmartTokens(address _convertibleToken) external view returns (address[]) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenSmartTokens(_convertibleToken); - } - - /** - * @dev returns the smart token associated with a given convertible token at a given index - * - * @param _index index - * @return smart token associated with the given convertible token at the given index - */ - function getConvertibleTokenSmartToken(address _convertibleToken, uint _index) external view returns (address) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenSmartToken(_convertibleToken, _index); - } - - /** - * @dev checks whether or not a given value is a smart token of a given convertible token - * - * @param _convertibleToken convertible token - * @param _value value - * @return true if the given value is a smart token of the given convertible token, false if not - */ - function isConvertibleTokenSmartToken(address _convertibleToken, address _value) external view returns (bool) { - return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isConvertibleTokenSmartToken(_convertibleToken, _value); - } - - /** - * @dev returns a list of converters for a given list of smart tokens - * this is a utility function that can be used to reduce the number of calls to the contract - * - * @param _smartTokens list of smart tokens - * @return list of converters - */ - function getConvertersBySmartTokens(address[] _smartTokens) external view returns (address[]) { - address[] memory converters = new address[](_smartTokens.length); - - for (uint i = 0; i < _smartTokens.length; i++) - converters[i] = ISmartToken(_smartTokens[i]).owner(); - - return converters; - } - - /** - * @dev checks whether or not a given converter is valid - * - * @param _converter converter - * @return true if the given converter is valid, false if not - */ - function isConverterValid(IBancorConverter _converter) public view returns (bool) { - ISmartToken token = ISmartTokenController(_converter).token(); - - // verifies the the smart token has a supply and that the converter is active - if (token.totalSupply() == 0 || token.owner() != address(_converter)) - return false; - - uint reserveTokenCount = _converter.connectorTokenCount(); - address[] memory reserveTokens = new address[](reserveTokenCount); - uint[] memory reserveRatios = new uint[](reserveTokenCount); - - // verifies that the converter holds balance in each of its reserves - for (uint i = 0; i < reserveTokenCount; i++) { - IERC20Token reserveToken = _converter.connectorTokens(i); - if (reserveToken.balanceOf(_converter) == 0) - return false; - reserveTokens[i] = reserveToken; - reserveRatios[i] = getReserveRatio(_converter, reserveToken); - } - - return getLiquidityPoolByReserveConfig(reserveTokens, reserveRatios) == ISmartToken(0); - } - - /** - * @dev searches for a liquidity pool with specific reserve tokens / ratios - * - * @param _reserveTokens reserve tokens - * @param _reserveRatios reserve ratios - * @return the liquidity pool, or zero if no such liquidity pool exists - */ - function getLiquidityPoolByReserveConfig(address[] memory _reserveTokens, uint[] memory _reserveRatios) public view returns (ISmartToken) { - // validate input - ensure that the number of reserve tokens match the number of reserve ratio - if (_reserveTokens.length == _reserveRatios.length && _reserveTokens.length > 1) { - // get the smart tokens of the least frequent token (optimization) - address[] memory convertibleTokenSmartTokens = getLeastFrequentTokenSmartTokens(_reserveTokens); - // search for a converter with an identical reserve-configuration - for (uint i = 0; i < convertibleTokenSmartTokens.length; i++) { - ISmartToken smartToken = ISmartToken(convertibleTokenSmartTokens[i]); - IBancorConverter converter = IBancorConverter(smartToken.owner()); - if (isConverterReserveConfigEqual(converter, _reserveTokens, _reserveRatios)) - return smartToken; - } - } - - return ISmartToken(0); - } - - /** - * @dev adds a smart token to the registry - * - * @param _smartToken smart token - */ - function addSmartToken(IBancorConverterRegistryData _converterRegistryData, address _smartToken) internal { - _converterRegistryData.addSmartToken(_smartToken); - emit SmartTokenAdded(_smartToken); - } - - /** - * @dev removes a smart token from the registry - * - * @param _smartToken smart token - */ - function removeSmartToken(IBancorConverterRegistryData _converterRegistryData, address _smartToken) internal { - _converterRegistryData.removeSmartToken(_smartToken); - emit SmartTokenRemoved(_smartToken); - } - - /** - * @dev adds a liquidity pool to the registry - * - * @param _liquidityPool liquidity pool - */ - function addLiquidityPool(IBancorConverterRegistryData _converterRegistryData, address _liquidityPool) internal { - _converterRegistryData.addLiquidityPool(_liquidityPool); - emit LiquidityPoolAdded(_liquidityPool); - } - - /** - * @dev removes a liquidity pool from the registry - * - * @param _liquidityPool liquidity pool - */ - function removeLiquidityPool(IBancorConverterRegistryData _converterRegistryData, address _liquidityPool) internal { - _converterRegistryData.removeLiquidityPool(_liquidityPool); - emit LiquidityPoolRemoved(_liquidityPool); - } - - /** - * @dev adds a convertible token to the registry - * - * @param _convertibleToken convertible token - * @param _smartToken associated smart token - */ - function addConvertibleToken(IBancorConverterRegistryData _converterRegistryData, address _convertibleToken, address _smartToken) internal { - _converterRegistryData.addConvertibleToken(_convertibleToken, _smartToken); - emit ConvertibleTokenAdded(_convertibleToken, _smartToken); - } - - /** - * @dev removes a convertible token from the registry - * - * @param _convertibleToken convertible token - * @param _smartToken associated smart token - */ - function removeConvertibleToken(IBancorConverterRegistryData _converterRegistryData, address _convertibleToken, address _smartToken) internal { - _converterRegistryData.removeConvertibleToken(_convertibleToken, _smartToken); - emit ConvertibleTokenRemoved(_convertibleToken, _smartToken); - } - - function getLeastFrequentTokenSmartTokens(address[] memory _tokens) private view returns (address[] memory) { - IBancorConverterRegistryData bancorConverterRegistryData = IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)); - - // find the token that has the smallest number of smart tokens - uint minSmartTokenCount = bancorConverterRegistryData.getConvertibleTokenSmartTokenCount(_tokens[0]); - address[] memory smartTokens = bancorConverterRegistryData.getConvertibleTokenSmartTokens(_tokens[0]); - for (uint i = 1; i < _tokens.length; i++) { - uint convertibleTokenSmartTokenCount = bancorConverterRegistryData.getConvertibleTokenSmartTokenCount(_tokens[i]); - if (minSmartTokenCount > convertibleTokenSmartTokenCount) { - minSmartTokenCount = convertibleTokenSmartTokenCount; - smartTokens = bancorConverterRegistryData.getConvertibleTokenSmartTokens(_tokens[i]); - } - } - return smartTokens; - } - - function isConverterReserveConfigEqual(IBancorConverter _converter, address[] memory _reserveTokens, uint[] memory _reserveRatios) private view returns (bool) { - if (_reserveTokens.length != _converter.connectorTokenCount()) - return false; - - for (uint i = 0; i < _reserveTokens.length; i++) { - if (_reserveRatios[i] != getReserveRatio(_converter, _reserveTokens[i])) - return false; - } - - return true; - } - - bytes4 private constant CONNECTORS_FUNC_SELECTOR = bytes4(uint256(keccak256("connectors(address)") >> (256 - 4 * 8))); - - function getReserveRatio(address _converter, address _reserveToken) private view returns (uint256) { - uint256[2] memory ret; - bytes memory data = abi.encodeWithSelector(CONNECTORS_FUNC_SELECTOR, _reserveToken); - - assembly { - let success := staticcall( - gas, // gas remaining - _converter, // destination address - add(data, 32), // input buffer (starts after the first 32 bytes in the `data` array) - mload(data), // input length (loaded from the first 32 bytes in the `data` array) - ret, // output buffer - 64 // output length - ) - if iszero(success) { - revert(0, 0) - } - } - - return ret[1]; - } -} +pragma solidity 0.4.26; +import '../utility/ContractRegistryClient.sol'; +import './interfaces/IBancorConverterRegistry.sol'; +import './interfaces/IBancorConverterRegistryData.sol'; +import '../token/interfaces/ISmartToken.sol'; +import '../token/interfaces/ISmartTokenController.sol'; + +/** + * @dev The BancorConverterRegistry maintains a list of all active converters in the Bancor Network. + * + * Since converters can be upgraded and thus their address can change, the registry actually keeps smart tokens internally and not the converters themselves. + * The active converter for each smart token can be easily accessed by querying the smart token owner. + * + * The registry exposes 3 differnet lists that can be accessed and iterated, based on the use-case of the caller: + * - Smart tokens - can be used to get all the latest / historical data in the network + * - Liquidity pools - can be used to get all liquidity pools for funding, liquidation etc. + * - Convertible tokens - can be used to get all tokens that can be converted in the network (excluding pool + * tokens), and for each one - all smart tokens that hold it in their reserves + * + * + * The contract fires events whenever one of the primitives is added to or removed from the registry + * + * The contract is upgradable. +*/ +contract BancorConverterRegistry is IBancorConverterRegistry, ContractRegistryClient { + /** + * @dev triggered when a smart token is added to the registry + * + * @param _smartToken smart token + */ + event SmartTokenAdded(address indexed _smartToken); + + /** + * @dev triggered when a smart token is removed from the registry + * + * @param _smartToken smart token + */ + event SmartTokenRemoved(address indexed _smartToken); + + /** + * @dev triggered when a liquidity pool is added to the registry + * + * @param _liquidityPool liquidity pool + */ + event LiquidityPoolAdded(address indexed _liquidityPool); + + /** + * @dev triggered when a liquidity pool is removed from the registry + * + * @param _liquidityPool liquidity pool + */ + event LiquidityPoolRemoved(address indexed _liquidityPool); + + /** + * @dev triggered when a convertible token is added to the registry + * + * @param _convertibleToken convertible token + * @param _smartToken associated smart token + */ + event ConvertibleTokenAdded(address indexed _convertibleToken, address indexed _smartToken); + + /** + * @dev triggered when a convertible token is removed from the registry + * + * @param _convertibleToken convertible token + * @param _smartToken associated smart token + */ + event ConvertibleTokenRemoved(address indexed _convertibleToken, address indexed _smartToken); + + /** + * @dev initializes a new BancorConverterRegistry instance + * + * @param _registry address of a contract registry contract + */ + constructor(IContractRegistry _registry) ContractRegistryClient(_registry) public { + } + + /** + * @dev adds a converter to the registry + * anyone can add a converter to the registry, as long as the converter is active and valid + * note that a liquidity pool converter can only be added if there's no existing pool with the same reserve configuration + * + * @param _converter converter + */ + function addConverter(IBancorConverter _converter) external { + // validate input + //require(isConverterValid(_converter)); + + IBancorConverterRegistryData converterRegistryData = IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)); + ISmartToken token = ISmartTokenController(_converter).token(); + uint reserveTokenCount = _converter.connectorTokenCount(); + + // add the smart token + addSmartToken(converterRegistryData, token); + if (reserveTokenCount > 1) + addLiquidityPool(converterRegistryData, token); + else + addConvertibleToken(converterRegistryData, token, token); + + // add all reserve tokens + for (uint i = 0; i < reserveTokenCount; i++) + addConvertibleToken(converterRegistryData, _converter.connectorTokens(i), token); + } + + /** + * @dev removes a converter from the registry + * anyone can remove invalid or inactive converters from the registry + * note that the owner can also remove valid converters + * + * @param _converter converter + */ + function removeConverter(IBancorConverter _converter) external { + // validate input + require(msg.sender == owner || !isConverterValid(_converter)); + + IBancorConverterRegistryData converterRegistryData = IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)); + ISmartToken token = ISmartTokenController(_converter).token(); + uint reserveTokenCount = _converter.connectorTokenCount(); + + // remove the smart token + removeSmartToken(converterRegistryData, token); + if (reserveTokenCount > 1) + removeLiquidityPool(converterRegistryData, token); + else + removeConvertibleToken(converterRegistryData, token, token); + + // remove all reserve tokens + for (uint i = 0; i < reserveTokenCount; i++) + removeConvertibleToken(converterRegistryData, _converter.connectorTokens(i), token); + } + + /** + * @dev returns the number of smart tokens in the registry + * + * @return number of smart tokens + */ + function getSmartTokenCount() external view returns (uint) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getSmartTokenCount(); + } + + /** + * @dev returns the list of smart tokens in the registry + * + * @return list of smart tokens + */ + function getSmartTokens() external view returns (address[]) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getSmartTokens(); + } + + /** + * @dev returns the smart token at a given index + * + * @param _index index + * @return smart token at the given index + */ + function getSmartToken(uint _index) external view returns (address) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getSmartToken(_index); + } + + /** + * @dev checks whether or not a given value is a smart token + * + * @param _value value + * @return true if the given value is a smart token, false if not + */ + function isSmartToken(address _value) external view returns (bool) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isSmartToken(_value); + } + + /** + * @dev returns the number of liquidity pools in the registry + * + * @return number of liquidity pools + */ + function getLiquidityPoolCount() external view returns (uint) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getLiquidityPoolCount(); + } + + /** + * @dev returns the list of liquidity pools in the registry + * + * @return list of liquidity pools + */ + function getLiquidityPools() external view returns (address[]) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getLiquidityPools(); + } + + /** + * @dev returns the liquidity pool at a given index + * + * @param _index index + * @return liquidity pool at the given index + */ + function getLiquidityPool(uint _index) external view returns (address) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getLiquidityPool(_index); + } + + /** + * @dev checks whether or not a given value is a liquidity pool + * + * @param _value value + * @return true if the given value is a liquidity pool, false if not + */ + function isLiquidityPool(address _value) external view returns (bool) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isLiquidityPool(_value); + } + + /** + * @dev returns the number of convertible tokens in the registry + * + * @return number of convertible tokens + */ + function getConvertibleTokenCount() external view returns (uint) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenCount(); + } + + /** + * @dev returns the list of convertible tokens in the registry + * + * @return list of convertible tokens + */ + function getConvertibleTokens() external view returns (address[]) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokens(); + } + + /** + * @dev returns the convertible token at a given index + * + * @param _index index + * @return convertible token at the given index + */ + function getConvertibleToken(uint _index) external view returns (address) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleToken(_index); + } + + /** + * @dev checks whether or not a given value is a convertible token + * + * @param _value value + * @return true if the given value is a convertible token, false if not + */ + function isConvertibleToken(address _value) external view returns (bool) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isConvertibleToken(_value); + } + + /** + * @dev returns the number of smart tokens associated with a given convertible token + * + * @param _convertibleToken convertible token + * @return number of smart tokens associated with the given convertible token + */ + function getConvertibleTokenSmartTokenCount(address _convertibleToken) external view returns (uint) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenSmartTokenCount(_convertibleToken); + } + + /** + * @dev returns the list of smart tokens associated with a given convertible token + * + * @param _convertibleToken convertible token + * @return list of smart tokens associated with the given convertible token + */ + function getConvertibleTokenSmartTokens(address _convertibleToken) external view returns (address[]) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenSmartTokens(_convertibleToken); + } + + /** + * @dev returns the smart token associated with a given convertible token at a given index + * + * @param _index index + * @return smart token associated with the given convertible token at the given index + */ + function getConvertibleTokenSmartToken(address _convertibleToken, uint _index) external view returns (address) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).getConvertibleTokenSmartToken(_convertibleToken, _index); + } + + /** + * @dev checks whether or not a given value is a smart token of a given convertible token + * + * @param _convertibleToken convertible token + * @param _value value + * @return true if the given value is a smart token of the given convertible token, false if not + */ + function isConvertibleTokenSmartToken(address _convertibleToken, address _value) external view returns (bool) { + return IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)).isConvertibleTokenSmartToken(_convertibleToken, _value); + } + + /** + * @dev returns a list of converters for a given list of smart tokens + * this is a utility function that can be used to reduce the number of calls to the contract + * + * @param _smartTokens list of smart tokens + * @return list of converters + */ + function getConvertersBySmartTokens(address[] _smartTokens) external view returns (address[]) { + address[] memory converters = new address[](_smartTokens.length); + + for (uint i = 0; i < _smartTokens.length; i++) + converters[i] = ISmartToken(_smartTokens[i]).owner(); + + return converters; + } + + /** + * @dev checks whether or not a given converter is valid + * + * @param _converter converter + * @return true if the given converter is valid, false if not + */ + function isConverterValid(IBancorConverter _converter) public view returns (bool) { + ISmartToken token = ISmartTokenController(_converter).token(); + + // verifies the the smart token has a supply and that the converter is active + if (token.totalSupply() == 0 || token.owner() != address(_converter)) + return false; + + uint reserveTokenCount = _converter.connectorTokenCount(); + address[] memory reserveTokens = new address[](reserveTokenCount); + uint[] memory reserveRatios = new uint[](reserveTokenCount); + + // verifies that the converter holds balance in each of its reserves + for (uint i = 0; i < reserveTokenCount; i++) { + IERC20Token reserveToken = _converter.connectorTokens(i); + if (reserveToken.balanceOf(_converter) == 0) + return false; + reserveTokens[i] = reserveToken; + reserveRatios[i] = getReserveRatio(_converter, reserveToken); + } + + return getLiquidityPoolByReserveConfig(reserveTokens, reserveRatios) == ISmartToken(0); + } + + /** + * @dev searches for a liquidity pool with specific reserve tokens / ratios + * + * @param _reserveTokens reserve tokens + * @param _reserveRatios reserve ratios + * @return the liquidity pool, or zero if no such liquidity pool exists + */ + function getLiquidityPoolByReserveConfig(address[] memory _reserveTokens, uint[] memory _reserveRatios) public view returns (ISmartToken) { + // validate input - ensure that the number of reserve tokens match the number of reserve ratio + if (_reserveTokens.length == _reserveRatios.length && _reserveTokens.length > 1) { + // get the smart tokens of the least frequent token (optimization) + address[] memory convertibleTokenSmartTokens = getLeastFrequentTokenSmartTokens(_reserveTokens); + // search for a converter with an identical reserve-configuration + for (uint i = 0; i < convertibleTokenSmartTokens.length; i++) { + ISmartToken smartToken = ISmartToken(convertibleTokenSmartTokens[i]); + IBancorConverter converter = IBancorConverter(smartToken.owner()); + if (isConverterReserveConfigEqual(converter, _reserveTokens, _reserveRatios)) + return smartToken; + } + } + + return ISmartToken(0); + } + + /** + * @dev adds a smart token to the registry + * + * @param _smartToken smart token + */ + function addSmartToken(IBancorConverterRegistryData _converterRegistryData, address _smartToken) internal { + _converterRegistryData.addSmartToken(_smartToken); + emit SmartTokenAdded(_smartToken); + } + + /** + * @dev removes a smart token from the registry + * + * @param _smartToken smart token + */ + function removeSmartToken(IBancorConverterRegistryData _converterRegistryData, address _smartToken) internal { + _converterRegistryData.removeSmartToken(_smartToken); + emit SmartTokenRemoved(_smartToken); + } + + /** + * @dev adds a liquidity pool to the registry + * + * @param _liquidityPool liquidity pool + */ + function addLiquidityPool(IBancorConverterRegistryData _converterRegistryData, address _liquidityPool) internal { + _converterRegistryData.addLiquidityPool(_liquidityPool); + emit LiquidityPoolAdded(_liquidityPool); + } + + /** + * @dev removes a liquidity pool from the registry + * + * @param _liquidityPool liquidity pool + */ + function removeLiquidityPool(IBancorConverterRegistryData _converterRegistryData, address _liquidityPool) internal { + _converterRegistryData.removeLiquidityPool(_liquidityPool); + emit LiquidityPoolRemoved(_liquidityPool); + } + + /** + * @dev adds a convertible token to the registry + * + * @param _convertibleToken convertible token + * @param _smartToken associated smart token + */ + function addConvertibleToken(IBancorConverterRegistryData _converterRegistryData, address _convertibleToken, address _smartToken) internal { + _converterRegistryData.addConvertibleToken(_convertibleToken, _smartToken); + emit ConvertibleTokenAdded(_convertibleToken, _smartToken); + } + + /** + * @dev removes a convertible token from the registry + * + * @param _convertibleToken convertible token + * @param _smartToken associated smart token + */ + function removeConvertibleToken(IBancorConverterRegistryData _converterRegistryData, address _convertibleToken, address _smartToken) internal { + _converterRegistryData.removeConvertibleToken(_convertibleToken, _smartToken); + emit ConvertibleTokenRemoved(_convertibleToken, _smartToken); + } + + function getLeastFrequentTokenSmartTokens(address[] memory _tokens) private view returns (address[] memory) { + IBancorConverterRegistryData bancorConverterRegistryData = IBancorConverterRegistryData(addressOf(BANCOR_CONVERTER_REGISTRY_DATA)); + + // find the token that has the smallest number of smart tokens + uint minSmartTokenCount = bancorConverterRegistryData.getConvertibleTokenSmartTokenCount(_tokens[0]); + address[] memory smartTokens = bancorConverterRegistryData.getConvertibleTokenSmartTokens(_tokens[0]); + for (uint i = 1; i < _tokens.length; i++) { + uint convertibleTokenSmartTokenCount = bancorConverterRegistryData.getConvertibleTokenSmartTokenCount(_tokens[i]); + if (minSmartTokenCount > convertibleTokenSmartTokenCount) { + minSmartTokenCount = convertibleTokenSmartTokenCount; + smartTokens = bancorConverterRegistryData.getConvertibleTokenSmartTokens(_tokens[i]); + } + } + return smartTokens; + } + + function isConverterReserveConfigEqual(IBancorConverter _converter, address[] memory _reserveTokens, uint[] memory _reserveRatios) private view returns (bool) { + if (_reserveTokens.length != _converter.connectorTokenCount()) + return false; + + for (uint i = 0; i < _reserveTokens.length; i++) { + if (_reserveRatios[i] != getReserveRatio(_converter, _reserveTokens[i])) + return false; + } + + return true; + } + + bytes4 private constant CONNECTORS_FUNC_SELECTOR = bytes4(uint256(keccak256("connectors(address)") >> (256 - 4 * 8))); + + function getReserveRatio(address _converter, address _reserveToken) private view returns (uint256) { + uint256[2] memory ret; + bytes memory data = abi.encodeWithSelector(CONNECTORS_FUNC_SELECTOR, _reserveToken); + + assembly { + let success := staticcall( + gas, // gas remaining + _converter, // destination address + add(data, 32), // input buffer (starts after the first 32 bytes in the `data` array) + mload(data), // input length (loaded from the first 32 bytes in the `data` array) + ret, // output buffer + 64 // output length + ) + if iszero(success) { + revert(0, 0) + } + } + + return ret[1]; + } +} diff --git a/contracts/old/NewBancorPool_old.sol b/contracts/old/NewBancorPool_old.sol new file mode 100644 index 0000000..935f2e7 --- /dev/null +++ b/contracts/old/NewBancorPool_old.sol @@ -0,0 +1,391 @@ +pragma solidity 0.4.26; + +// Bancor-Protocol +import "./bancor-protocol/utility/ContractRegistry.sol"; // Step #1: Initial Setup +//import "./bancor-protocol/utility/ContractRegistryClient.sol"; +import "./bancor-protocol/token/SmartToken.sol"; // Step #2: Smart Relay Token Deployment +import "./bancor-protocol/token/SmartTokenController.sol"; // Step #7: Converters Registry Listing +import "./bancor-protocol/token/interfaces/ISmartToken.sol"; // Step #7: Converters Registry Listing +import "./bancor-protocol/converter/BancorConverter.sol"; // Step #3: Converter Deployment +import "./bancor-protocol/converter/BancorConverterFactory.sol"; // Step #5: Activation and Step #6: Multisig Ownership +import "./bancor-protocol/converter/interfaces/IBancorConverter.sol"; +import "./bancor-protocol/converter/interfaces/IBancorConverterFactory.sol"; + +import "./bancor-protocol/converter/BancorConverterRegistry.sol"; // Step #7: Converters Registry Listing +import "./bancor-protocol/converter/BancorConverterRegistryData.sol"; + +//import "./bancor-protocol/token/ERC20Token.sol"; +import './bancor-protocol/token/interfaces/IERC20Token.sol'; + +import './bancor-protocol/utility/Managed.sol'; +import './bancor-protocol/converter/BancorFormula.sol'; + + +// Storage +import "./storage/BnStorage.sol"; +import "./storage/BnConstants.sol"; + + +contract NewBancorPool is BnStorage, BnConstants, Managed { + + ContractRegistry public contractRegistry; + //ContractRegistryClient public contractRegistryClient; + + SmartToken public smartToken; + BancorConverter public bancorConverter; + BancorConverterFactory public bancorConverterFactory; + BancorConverterRegistry public bancorConverterRegistry; + BancorConverterRegistryData public bancorConverterRegistryData; + + BancorFormula public bancorFormula; + + IERC20Token public token; + + address contractRegistryAddr; + + address BNTtokenAddr; + address ERC20tokenAddr; + address cDAItokenAddr; // cToken from compound pool + + address smartTokenAddr; + + address bancorConverterAddr; + + address BANCOR_CONVERTER_REGISTRY_DATA; + address BANCOR_FORMULA; // ContractAddress of BancorFormula.sol + + + constructor( + address _contractRegistry, + //address _contractRegistryClient, + address _BNTtokenAddr, + address _ERC20tokenAddr, + address _cDAItokenAddr, + address _smartToken, + address _bancorConverter, + //address _bancorConverterFactory, + address _bancorConverterRegistry, + address _bancorConverterRegistryData, + address _bancorFormula + ) + public + { + // Step #1: Initial Setup + contractRegistry = ContractRegistry(_contractRegistry); + //contractRegistryClient = ContractRegistryClient(_contractRegistryClient); + + contractRegistryAddr = _contractRegistry; + + BNTtokenAddr = _BNTtokenAddr; + ERC20tokenAddr = _ERC20tokenAddr; + cDAItokenAddr = _cDAItokenAddr; // cToken from compound pool + + smartTokenAddr = _smartToken; + + bancorConverterAddr = _bancorConverter; + + BANCOR_CONVERTER_REGISTRY_DATA = _bancorConverterRegistryData; + BANCOR_FORMULA = _bancorFormula; + + token = IERC20Token(ERC20tokenAddr); + + // Step #2: Smart Relay Token Deployment + smartToken = SmartToken(_smartToken); + + // Step #3: Converter Deployment + bancorConverter = BancorConverter(_bancorConverter); + + // Step #5: Activation and Step #6: Multisig Ownership + //bancorConverterFactory = BancorConverterFactory(_bancorConverterFactory); + + // Step #7: Converters Registry Listing + bancorConverterRegistry = BancorConverterRegistry(_bancorConverterRegistry); + } + + + function testFunc() public returns (uint256 _hundredPercent) { + return BnConstants.hundredPercent; + } + + function testFuncCallBancorNetworkContractAddr() public view returns (address _bancorNetwork) { + address bancorNetwork; + bancorNetwork = contractRegistry.addressOf('BancorNetwork'); + return bancorNetwork; + } + + // function testFuncCallBancorConverterFactoryContractAddr() public view returns (IBancorConverterFactory) { + // address bancorConverterFactory; + // //IBancorConverterFactory bancorConverterFactory = IBancorConverterFactory(addressOf(BANCOR_CONVERTER_FACTORY)); + // bancorConverterFactory = contractRegistry.addressOf('BancorConverterFactory'); + // return bancorConverterFactory; + // } + + function testFuncCallBancorConverterUpgraderContractAddr() public view returns (address _bancorConverterUpgrader) { + address bancorConverterUpgrader; + bancorConverterUpgrader = contractRegistry.addressOf('BancorConverterUpgrader'); + return bancorConverterUpgrader; + } + + function _addConverter() public { + bancorConverterRegistry.addConverter(IBancorConverter(bancorConverterAddr)); + } + + + + + /*** + * @notice - Integrate pools with lending protocols (e.g., lend pool tokens to Compound) to hedge risk for stakers + * https://docs.bancor.network/user-guides/token-integration/how-to-create-a-bancor-liquidity-pool + **/ + function integratePoolWithLendingProtocol( + bytes32 _contractName1, + //string _contractName2, + address receiverAddr, + uint256 amountOfSmartToken + ) public returns (bool) { + // [In progress]: Integrate with lending pool of compound (cToken) + + // Step #1: Initial Setup + address token1; + //address token2; + + token1 = contractRegistry.addressOf(_contractName1); + //token2 = contractRegistry.addressOf(_contractName2); + + // Step #2: Smart Relay Token Deployment + smartToken.issue(msg.sender, amountOfSmartToken); + smartToken.transfer(receiverAddr, amountOfSmartToken); + + // Step #3: Converter Deployment + //uint index = 0; + uint32 reserveRatio = 10; // The case of this, I specify 10% as percentage of ratio. (After I need to divide by 100) + //uint32 _conversionFee = 1000; // Fee: 1,000 (0.1%) + + addConnector(IERC20Token(ERC20tokenAddr), reserveRatio, true); + //bancorConverter.addConnector(IERC20Token(ERC20tokenAddr), reserveRatio, true); + //bancorConverter.setConversionFee(_conversionFee); + + // Step #4: Funding & Initial Supply + uint256 fundedAmount = 100; + fund(fundedAmount); + //bancorConverter.fund(fundedAmount); + + // Step #5: Activation + // Step #6: Multisig Ownership + address _converterAddress; // @notice - This variable is for receiving return value of createConverter() below + uint32 _maxConversionFee = 1; + // _converterAddress = bancorConverterFactory.createConverter(smartToken, + // contractRegistry, + // _maxConversionFee, + // token, + // reserveRatio); + + // Step #7: Converters Registry Listing + bancorConverterRegistry.addConverter(IBancorConverter(_converterAddress)); + } + + + + + /*********************************************************** + * @notice - Internal function from BancorConverter.sol + ***********************************************************/ + uint32 private constant RATIO_RESOLUTION = 1000000; + uint64 private constant CONVERSION_FEE_RESOLUTION = 1000000; + + /** + * @dev version number + */ + uint16 public version = 25; + + IWhitelist public conversionWhitelist; // whitelist contract with list of addresses that are allowed to use the converter + IERC20Token[] public reserveTokens; // ERC20 standard token addresses (prior version 17, use 'connectorTokens' instead) + + struct Reserve { + uint256 virtualBalance; // reserve virtual balance + uint32 ratio; // reserve ratio, represented in ppm, 1-1000000 + bool isVirtualBalanceEnabled; // true if virtual balance is enabled, false if not + bool isSaleEnabled; // is sale of the reserve token enabled, can be set by the owner + bool isSet; // used to tell if the mapping element is defined + } + mapping (address => Reserve) public reserves; // reserve token addresses -> reserve data (prior version 17, use 'connectors' instead) + + uint32 private totalReserveRatio = 0; // used to efficiently prevent increasing the total reserve ratio above 100% + uint32 public maxConversionFee = 0; // maximum conversion fee for the lifetime of the contract, + // represented in ppm, 0...1000000 (0 = no fee, 100 = 0.01%, 1000000 = 100%) + uint32 public conversionFee = 0; // current conversion fee, represented in ppm, 0...maxConversionFee + bool public conversionsEnabled = true; // deprecated, backward compatibility + + + // event Conversion( + // address indexed _fromToken, + // address indexed _toToken, + // address indexed _trader, + // uint256 _amount, + // uint256 _return, + // int256 _conversionFee + // ); + + event PriceDataUpdate( + address indexed _connectorToken, + uint256 _tokenSupply, + uint256 _connectorBalance, + uint32 _connectorWeight + ); + + event SmartTokenAdded(address indexed _smartToken); + event LiquidityPoolAdded(address indexed _liquidityPool); + event ConvertibleTokenAdded(address indexed _convertibleToken, address indexed _smartToken); + + + // validates reserve ratio + modifier validReserveRatio(uint32 _ratio) { + require(_ratio > 0 && _ratio <= RATIO_RESOLUTION); + _; + } + + // allows execution only on a multiple-reserve converter + modifier multipleReservesOnly { + require(reserveTokens.length > 1); + _; + } + + + function addConnector(IERC20Token _token, uint32 _weight, bool /*_enableVirtualBalance*/) public { + addReserve(_token, _weight); + } + + function addReserve(IERC20Token _token, uint32 _ratio) + public + ownerOnly + //inactive + //validAddress(_token) + //notThis(_token) + validReserveRatio(_ratio) + { + //require(_token != token && !reserves[_token].isSet && totalReserveRatio + _ratio <= RATIO_RESOLUTION); // validate input + + reserves[_token].ratio = _ratio; + reserves[_token].isVirtualBalanceEnabled = false; + reserves[_token].virtualBalance = 0; + reserves[_token].isSaleEnabled = true; + reserves[_token].isSet = true; + reserveTokens.push(_token); + totalReserveRatio += _ratio; + } + + + /** + * @dev updates the current conversion fee + * can only be called by the manager + * + * @param _conversionFee new conversion fee, represented in ppm + */ + // event ConversionFeeUpdate(uint32 _prevFee, uint32 _newFee); + + // function setConversionFee(uint32 _conversionFee) + // public + // ownerOrManagerOnly + // { + // require(_conversionFee >= 0 && _conversionFee <= maxConversionFee); + // emit ConversionFeeUpdate(conversionFee, _conversionFee); + // conversionFee = _conversionFee; + // } + + + /** + * @dev buys the token with all reserve tokens using the same percentage + * for example, if the caller increases the supply by 10%, + * then it will cost an amount equal to 10% of each reserve token balance + * note that the function can be called only when conversions are enabled + * + * @param _amount amount to increase the supply by (in the smart token) + */ + function fund(uint256 _amount) + public + multipleReservesOnly + { + uint256 supply = smartToken.totalSupply(); + IBancorFormula formula = IBancorFormula(BANCOR_FORMULA); + + // iterate through the reserve tokens and transfer a percentage equal to the ratio between _amount + // and the total supply in each reserve from the caller to the converter + IERC20Token reserveToken; + uint256 reserveBalance; + uint256 reserveAmount; + for (uint16 i = 0; i < reserveTokens.length; i++) { + reserveToken = reserveTokens[i]; + reserveBalance = reserveToken.balanceOf(this); + reserveAmount = formula.calculateFundCost(supply, reserveBalance, totalReserveRatio, _amount); + + Reserve storage reserve = reserves[reserveToken]; + + // transfer funds from the caller in the reserve token + ensureTransferFrom(reserveToken, msg.sender, this, reserveAmount); + + // dispatch price data update for the smart token/reserve + emit PriceDataUpdate(reserveToken, supply + _amount, reserveBalance + reserveAmount, reserve.ratio); + } + + // issue new funds to the caller in the smart token + smartToken.issue(msg.sender, _amount); + } + + function ensureTransferFrom(IERC20Token _token, address _from, address _to, uint256 _amount) private { + // We must assume that functions `transfer` and `transferFrom` do not return anything, + // because not all tokens abide the requirement of the ERC20 standard to return success or failure. + // This is because in the current compiler version, the calling contract can handle more returned data than expected but not less. + // This may change in the future, so that the calling contract will revert if the size of the data is not exactly what it expects. + uint256 prevBalance = _token.balanceOf(_to); + if (_from == address(this)) + INonStandardERC20(_token).transfer(_to, _amount); + else + INonStandardERC20(_token).transferFrom(_from, _to, _amount); + uint256 postBalance = _token.balanceOf(_to); + require(postBalance > prevBalance); + } + + + + function addConverter() external { + // validate input + //require(isConverterValid(_converter)); + + BancorConverterRegistryData converterRegistryData = BancorConverterRegistryData(BANCOR_CONVERTER_REGISTRY_DATA); + uint reserveTokenCount = connectorTokenCount(); + + // add the smart token + addSmartToken(converterRegistryData, smartTokenAddr); + if (reserveTokenCount > 1) + addLiquidityPool(converterRegistryData, smartTokenAddr); + else + addConvertibleToken(converterRegistryData, smartTokenAddr, smartTokenAddr); + + // add all reserve tokens + for (uint i = 0; i < reserveTokenCount; i++) + addConvertibleToken(converterRegistryData, reserveTokens[i], token); + } + + function connectorTokenCount() public view returns (uint16) { + return reserveTokenCount(); + } + + function reserveTokenCount() public view returns (uint16) { + return uint16(reserveTokens.length); + } + + function addSmartToken(IBancorConverterRegistryData _converterRegistryData, address _smartToken) internal { + _converterRegistryData.addSmartToken(_smartToken); + emit SmartTokenAdded(_smartToken); + } + + function addLiquidityPool(IBancorConverterRegistryData _converterRegistryData, address _liquidityPool) internal { + _converterRegistryData.addLiquidityPool(_liquidityPool); + emit LiquidityPoolAdded(_liquidityPool); + } + + function addConvertibleToken(IBancorConverterRegistryData _converterRegistryData, address _convertibleToken, address _smartToken) internal { + _converterRegistryData.addConvertibleToken(_convertibleToken, _smartToken); + emit ConvertibleTokenAdded(_convertibleToken, _smartToken); + } +} diff --git a/migrations_old/6_deploy_new_bancor_pool_old.js b/migrations_old/6_deploy_new_bancor_pool_old.js new file mode 100644 index 0000000..5621770 --- /dev/null +++ b/migrations_old/6_deploy_new_bancor_pool_old.js @@ -0,0 +1,39 @@ +var NewBancorPool = artifacts.require("NewBancorPool"); + +/*** + * @notice - This is ContractAddress on Ropsten + * @ref - https://support.bancor.network/hc/en-us/articles/360010410399-Ethereum-Ropsten-Network- + * @ref - https://compound.finance/developers + **/ +const _contractRegistry = '0x8a69A7d7507F8c4a9dD5dEB9B687B30D2b30A011' +const _BNTtoken = '0x9C7d1F4a027C64Af951858FD0F9CB3C91e008829' +const _ERC20token = '0xad6d458402f60fd3bd25163575031acdce07538d' // DAI on Ropsten +const _cDAI = '0x2b536482a01e620ee111747f8334b395a42a555e' + +var SmartToken = artifacts.require("SmartToken") +//var BancorConverter = artifacts.require("BancorConverter") +//var BancorConverterFactory = artifacts.require("BancorConverterFactory") +const _smartToken = SmartToken.address +const _bancorConverter = '0x7ee55cD9AeFA96ED3450b93d23EED33A27826dA4' +//const _bancorConverterFactory = BancorConverterFactory.address +const _bancorConverterRegistry = '0x8bf88CFed154b0f6dbdC64cb35c829698b26c869' +var BancorConverterRegistryData = artifacts.require("BancorConverterRegistryData"); +const _bancorConverterRegistryData = BancorConverterRegistryData.address; +const _bancorFormula = '0xbD2D011492E3b7bdc0d27b4aB2053f58FF6459d3' + + +module.exports = function(deployer) { + deployer.deploy( + NewBancorPool, + _contractRegistry, + _BNTtoken, + _ERC20token, + _cDAI, + _smartToken, + _bancorConverter, + //_bancorConverterFactory, + _bancorConverterRegistry, + _bancorConverterRegistryData, + _bancorFormula + ); +};