From 9e8ec010e84aaaec11488fcf6fb0def3ba3c24c0 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Fri, 24 May 2019 20:14:12 +0530 Subject: [PATCH 1/2] Added custom oracles to USDTSTO --- .../modules/STO/USDTiered/USDTieredSTO.sol | 19 ++++++++++++++++--- .../STO/USDTiered/USDTieredSTOStorage.sol | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/contracts/modules/STO/USDTiered/USDTieredSTO.sol b/contracts/modules/STO/USDTiered/USDTieredSTO.sol index 67b2fc6f1..c1a142093 100644 --- a/contracts/modules/STO/USDTiered/USDTieredSTO.sol +++ b/contracts/modules/STO/USDTiered/USDTieredSTO.sol @@ -190,6 +190,18 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { _modifyAddresses(_wallet, _treasuryWallet, _usdTokens); } + /** + * @dev Modifies Oracle address. + * By default, Polymath oracles are used but issuer can overide them using this function + * @param _currency Actual currency + * @param _denominatedCurrency denominated currency + * @param _oracleAddress address of the oracle + */ + function modifyOracle(bytes32 _currency, bytes32 _denominatedCurrency, address _oracleAddress) external { + _onlySecurityTokenOwner(); + customOracles[_currency][_denominatedCurrency] = _oracleAddress; + } + function _modifyLimits(uint256 _nonAccreditedLimitUSD, uint256 _minimumInvestmentUSD) internal { minimumInvestmentUSD = _minimumInvestmentUSD; nonAccreditedLimitUSD = _nonAccreditedLimitUSD; @@ -757,8 +769,9 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { return this.configure.selector; } - function _getOracle(bytes32 _currency, bytes32 _denominatedCurrency) internal view returns(address) { - return IPolymathRegistry(ISecurityToken(securityToken).polymathRegistry()).getAddress(oracleKeys[_currency][_denominatedCurrency]); + function _getOracle(bytes32 _currency, bytes32 _denominatedCurrency) internal view returns(address oracleAddress) { + oracleAddress = customOracles[_currency][_denominatedCurrency]; + if (oracleAddress == address(0)) + oracleAddress = IPolymathRegistry(ISecurityToken(securityToken).polymathRegistry()).getAddress(oracleKeys[_currency][_denominatedCurrency]); } - } diff --git a/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol b/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol index 75a1f6d1c..6b4330b48 100644 --- a/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol +++ b/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol @@ -74,4 +74,5 @@ contract USDTieredSTOStorage { // Array of Tiers Tier[] public tiers; + mapping(bytes32 => mapping(bytes32 => address)) customOracles; } From a1d797e6287567ede271b6976b265df0ada7a780 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Mon, 27 May 2019 10:38:04 +0530 Subject: [PATCH 2/2] Updated custom oracles logic --- .../modules/STO/USDTiered/USDTieredSTO.sol | 13 ++++--- .../STO/USDTiered/USDTieredSTOStorage.sol | 1 + test/p_usd_tiered_sto.js | 36 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/contracts/modules/STO/USDTiered/USDTieredSTO.sol b/contracts/modules/STO/USDTiered/USDTieredSTO.sol index c1a142093..c042ee127 100644 --- a/contracts/modules/STO/USDTiered/USDTieredSTO.sol +++ b/contracts/modules/STO/USDTiered/USDTieredSTO.sol @@ -193,13 +193,18 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { /** * @dev Modifies Oracle address. * By default, Polymath oracles are used but issuer can overide them using this function - * @param _currency Actual currency - * @param _denominatedCurrency denominated currency + * Set _oracleAddress to 0x0 to fallback to using Polymath oracles + * @param _fundRaiseType Actual currency * @param _oracleAddress address of the oracle */ - function modifyOracle(bytes32 _currency, bytes32 _denominatedCurrency, address _oracleAddress) external { + function modifyOracle(FundRaiseType _fundRaiseType, address _oracleAddress) external { _onlySecurityTokenOwner(); - customOracles[_currency][_denominatedCurrency] = _oracleAddress; + if (_fundRaiseType == FundRaiseType.ETH) { + customOracles[bytes32("ETH")][bytes32("USD")] = _oracleAddress; + } else { + require(_fundRaiseType == FundRaiseType.POLY, "Invalid currency"); + customOracles[bytes32("POLY")][bytes32("USD")] = _oracleAddress; + } } function _modifyLimits(uint256 _nonAccreditedLimitUSD, uint256 _minimumInvestmentUSD) internal { diff --git a/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol b/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol index 6b4330b48..15cc553ae 100644 --- a/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol +++ b/contracts/modules/STO/USDTiered/USDTieredSTOStorage.sol @@ -74,5 +74,6 @@ contract USDTieredSTOStorage { // Array of Tiers Tier[] public tiers; + // Optional custom Oracles. mapping(bytes32 => mapping(bytes32 => address)) customOracles; } diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 9148dfe7a..f7b014180 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -35,6 +35,8 @@ contract("USDTieredSTO", async (accounts) => { let ETH = 0; let POLY = 1; let DAI = 2; + let oldEthRate; + let oldPolyRate; let MESSAGE = "Transaction Should Fail!"; const GAS_PRICE = 0; @@ -909,6 +911,40 @@ contract("USDTieredSTO", async (accounts) => { }); describe("Test modifying configuration", async () => { + it("Should not allow unauthorized address to change oracle address", async () => { + let stoId = 3; + await catchRevert(I_USDTieredSTO_Array[stoId].modifyOracle(ETH, address_zero, { from: ACCREDITED1 })); + }); + + it("Should not allow to change oracle address for currencies other than ETH and POLY", async () => { + let stoId = 3; + await catchRevert(I_USDTieredSTO_Array[stoId].modifyOracle(DAI, address_zero, { from: ISSUER })); + }); + + it("Should allow to change oracle address for ETH", async () => { + let stoId = 3; + oldEthRate = await I_USDTieredSTO_Array[stoId].getRate.call(ETH); + let I_USDOracle2 = await MockOracle.new(address_zero, web3.utils.fromAscii("ETH"), web3.utils.fromAscii("USD"), e18, { from: POLYMATH }); + await I_USDTieredSTO_Array[stoId].modifyOracle(ETH, I_USDOracle2.address, { from: ISSUER }); + assert.equal((await I_USDTieredSTO_Array[stoId].getRate.call(ETH)).toString(), e18.toString()); + }); + + it("Should allow to change oracle address for POLY", async () => { + let stoId = 3; + oldPolyRate = await I_USDTieredSTO_Array[stoId].getRate.call(POLY); + let I_POLYOracle2 = await MockOracle.new(I_PolyToken.address, web3.utils.fromAscii("POLY"), web3.utils.fromAscii("USD"), e18, { from: POLYMATH }); + await I_USDTieredSTO_Array[stoId].modifyOracle(POLY, I_POLYOracle2.address, { from: ISSUER }); + assert.equal((await I_USDTieredSTO_Array[stoId].getRate.call(POLY)).toString(), e18.toString()); + }); + + it("Should use official oracles when custom oracle is set to 0x0", async () => { + let stoId = 3; + await I_USDTieredSTO_Array[stoId].modifyOracle(ETH, address_zero, { from: ISSUER }); + await I_USDTieredSTO_Array[stoId].modifyOracle(POLY, address_zero, { from: ISSUER }); + assert.equal((await I_USDTieredSTO_Array[stoId].getRate.call(ETH)).toString(), oldEthRate.toString()); + assert.equal((await I_USDTieredSTO_Array[stoId].getRate.call(POLY)).toString(), oldPolyRate.toString()); + }); + it("Should successfully change config before startTime - funding", async () => { let stoId = 3; await I_USDTieredSTO_Array[stoId].modifyFunding([0], { from: ISSUER });