aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src
diff options
context:
space:
mode:
authorAmir Bandeali <abandeali1@gmail.com>2018-08-22 11:43:23 +0800
committerGitHub <noreply@github.com>2018-08-22 11:43:23 +0800
commit80e52464a6fdf9576776214f77e46d441b959b06 (patch)
tree964c5c3cb0eeacf70bece4e485b5fddceea2adb4 /packages/contracts/src
parentf53157414f144a7ea8c24126c9d75d3168228130 (diff)
parent3760eb5bafcc0980b3a42dd5f10e745390702b16 (diff)
downloaddexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.gz
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.bz2
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.lz
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.xz
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.tar.zst
dexon-sol-tools-80e52464a6fdf9576776214f77e46d441b959b06.zip
Merge pull request #985 from 0xProject/feature/contracts/orderValidator
[contracts] Add contract for batch validating orders
Diffstat (limited to 'packages/contracts/src')
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/Forwarder.sol (renamed from packages/contracts/src/2.0.0/forwarder/Forwarder.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinAssets.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinAssets.sol)10
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinExchangeWrapper.sol)8
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinForwarderCore.sol)8
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol (renamed from packages/contracts/src/2.0.0/forwarder/MixinWeth.sol)2
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IAssets.sol (renamed from packages/contracts/src/2.0.0/forwarder/interfaces/IAssets.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarder.sol (renamed from packages/contracts/src/2.0.0/forwarder/interfaces/IForwarder.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarderCore.sol (renamed from packages/contracts/src/2.0.0/forwarder/interfaces/IForwarderCore.sol)4
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibConstants.sol (renamed from packages/contracts/src/2.0.0/forwarder/libs/LibConstants.sol)8
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibForwarderErrors.sol (renamed from packages/contracts/src/2.0.0/forwarder/libs/LibForwarderErrors.sol)2
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MAssets.sol (renamed from packages/contracts/src/2.0.0/forwarder/mixins/MAssets.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MExchangeWrapper.sol (renamed from packages/contracts/src/2.0.0/forwarder/mixins/MExchangeWrapper.sol)4
-rw-r--r--packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MWeth.sol (renamed from packages/contracts/src/2.0.0/forwarder/mixins/MWeth.sol)0
-rw-r--r--packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol218
14 files changed, 241 insertions, 23 deletions
diff --git a/packages/contracts/src/2.0.0/forwarder/Forwarder.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/Forwarder.sol
index 6b17bb29b..6b17bb29b 100644
--- a/packages/contracts/src/2.0.0/forwarder/Forwarder.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/Forwarder.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinAssets.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinAssets.sol
index e06f9a8e3..d6a38aa6e 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinAssets.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinAssets.sol
@@ -18,10 +18,10 @@
pragma solidity 0.4.24;
-import "../utils/LibBytes/LibBytes.sol";
-import "../utils/Ownable/Ownable.sol";
-import "../tokens/ERC20Token/IERC20Token.sol";
-import "../tokens/ERC721Token/IERC721Token.sol";
+import "../../utils/LibBytes/LibBytes.sol";
+import "../../utils/Ownable/Ownable.sol";
+import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../tokens/ERC721Token/IERC721Token.sol";
import "./libs/LibConstants.sol";
import "./mixins/MAssets.sol";
@@ -67,7 +67,7 @@ contract MixinAssets is
} else if (proxyId == ERC721_DATA_ID) {
transferERC721Token(assetData, amount);
} else {
- revert("UNSUPPORTED_TOKEN_PROXY");
+ revert("UNSUPPORTED_ASSET_PROXY");
}
}
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinExchangeWrapper.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol
index 4584bb840..218713d3c 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinExchangeWrapper.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol
@@ -21,10 +21,10 @@ pragma experimental ABIEncoderV2;
import "./libs/LibConstants.sol";
import "./mixins/MExchangeWrapper.sol";
-import "../protocol/Exchange/libs/LibAbiEncoder.sol";
-import "../protocol/Exchange/libs/LibOrder.sol";
-import "../protocol/Exchange/libs/LibFillResults.sol";
-import "../protocol/Exchange/libs/LibMath.sol";
+import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
+import "../../protocol/Exchange/libs/LibOrder.sol";
+import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../protocol/Exchange/libs/LibMath.sol";
contract MixinExchangeWrapper is
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinForwarderCore.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol
index 93cbf79be..42cec4d36 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinForwarderCore.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol
@@ -24,10 +24,10 @@ import "./mixins/MWeth.sol";
import "./mixins/MAssets.sol";
import "./mixins/MExchangeWrapper.sol";
import "./interfaces/IForwarderCore.sol";
-import "../utils/LibBytes/LibBytes.sol";
-import "../protocol/Exchange/libs/LibOrder.sol";
-import "../protocol/Exchange/libs/LibFillResults.sol";
-import "../protocol/Exchange/libs/LibMath.sol";
+import "../../utils/LibBytes/LibBytes.sol";
+import "../../protocol/Exchange/libs/LibOrder.sol";
+import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../protocol/Exchange/libs/LibMath.sol";
contract MixinForwarderCore is
diff --git a/packages/contracts/src/2.0.0/forwarder/MixinWeth.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol
index e07940776..93e85e599 100644
--- a/packages/contracts/src/2.0.0/forwarder/MixinWeth.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol
@@ -18,7 +18,7 @@
pragma solidity 0.4.24;
-import "../protocol/Exchange/libs/LibMath.sol";
+import "../../protocol/Exchange/libs/LibMath.sol";
import "./libs/LibConstants.sol";
import "./mixins/MWeth.sol";
diff --git a/packages/contracts/src/2.0.0/forwarder/interfaces/IAssets.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IAssets.sol
index 1e034c003..1e034c003 100644
--- a/packages/contracts/src/2.0.0/forwarder/interfaces/IAssets.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IAssets.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarder.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarder.sol
index f5a26e2ba..f5a26e2ba 100644
--- a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarder.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarder.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarderCore.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarderCore.sol
index 3ecbb133b..74c7da01d 100644
--- a/packages/contracts/src/2.0.0/forwarder/interfaces/IForwarderCore.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/interfaces/IForwarderCore.sol
@@ -19,8 +19,8 @@
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../../protocol/Exchange/libs/LibOrder.sol";
+import "../../../protocol/Exchange/libs/LibFillResults.sol";
contract IForwarderCore {
diff --git a/packages/contracts/src/2.0.0/forwarder/libs/LibConstants.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibConstants.sol
index fb9691fe8..704e42ce3 100644
--- a/packages/contracts/src/2.0.0/forwarder/libs/LibConstants.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibConstants.sol
@@ -18,10 +18,10 @@
pragma solidity 0.4.24;
-import "../../utils/LibBytes/LibBytes.sol";
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../tokens/EtherToken/IEtherToken.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../../utils/LibBytes/LibBytes.sol";
+import "../../../protocol/Exchange/interfaces/IExchange.sol";
+import "../../../tokens/EtherToken/IEtherToken.sol";
+import "../../../tokens/ERC20Token/IERC20Token.sol";
contract LibConstants {
diff --git a/packages/contracts/src/2.0.0/forwarder/libs/LibForwarderErrors.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibForwarderErrors.sol
index cdfb77a0b..fb3ade1db 100644
--- a/packages/contracts/src/2.0.0/forwarder/libs/LibForwarderErrors.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/libs/LibForwarderErrors.sol
@@ -27,7 +27,7 @@ contract LibForwarderErrors {
string constant OVERSOLD_WETH = "OVERSOLD_WETH"; // More WETH sold than provided with current message call.
string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired purchase amount not completely filled (required for ZRX fees only).
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Asset transfer failed.
- string constant UNSUPPORTED_TOKEN_PROXY = "UNSUPPORTED_TOKEN_PROXY"; // Proxy in assetData not supported.
+ string constant UNSUPPORTED_ASSET_PROXY = "UNSUPPORTED_ASSET_PROXY"; // Proxy in assetData not supported.
string constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY = "DEFAULT_FUNCTION_WETH_CONTRACT_ONLY"; // Fallback function may only be used for WETH withdrawals.
string constant INVALID_MSG_VALUE = "INVALID_MSG_VALUE"; // msg.value must be greater than 0.
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Amount must equal 1.
diff --git a/packages/contracts/src/2.0.0/forwarder/mixins/MAssets.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MAssets.sol
index 83636432a..83636432a 100644
--- a/packages/contracts/src/2.0.0/forwarder/mixins/MAssets.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MAssets.sol
diff --git a/packages/contracts/src/2.0.0/forwarder/mixins/MExchangeWrapper.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MExchangeWrapper.sol
index 360dea0e4..13c26b03a 100644
--- a/packages/contracts/src/2.0.0/forwarder/mixins/MExchangeWrapper.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MExchangeWrapper.sol
@@ -19,8 +19,8 @@
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
+import "../../../protocol/Exchange/libs/LibOrder.sol";
+import "../../../protocol/Exchange/libs/LibFillResults.sol";
contract MExchangeWrapper {
diff --git a/packages/contracts/src/2.0.0/forwarder/mixins/MWeth.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MWeth.sol
index 88e77be4e..88e77be4e 100644
--- a/packages/contracts/src/2.0.0/forwarder/mixins/MWeth.sol
+++ b/packages/contracts/src/2.0.0/extensions/Forwarder/mixins/MWeth.sol
diff --git a/packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol b/packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol
new file mode 100644
index 000000000..a18345245
--- /dev/null
+++ b/packages/contracts/src/2.0.0/extensions/OrderValidator/OrderValidator.sol
@@ -0,0 +1,218 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
+
+import "../../protocol/Exchange/interfaces/IExchange.sol";
+import "../../protocol/Exchange/libs/LibOrder.sol";
+import "../../tokens/ERC20Token/IERC20Token.sol";
+import "../../tokens/ERC721Token/IERC721Token.sol";
+import "../../utils/LibBytes/LibBytes.sol";
+
+
+contract OrderValidator {
+
+ bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
+ bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
+
+ using LibBytes for bytes;
+
+ struct TraderInfo {
+ uint256 makerBalance; // Maker's balance of makerAsset
+ uint256 makerAllowance; // Maker's allowance to corresponding AssetProxy
+ uint256 takerBalance; // Taker's balance of takerAsset
+ uint256 takerAllowance; // Taker's allowance to corresponding AssetProxy
+ uint256 makerZrxBalance; // Maker's balance of ZRX
+ uint256 makerZrxAllowance; // Maker's allowance of ZRX to ERC20Proxy
+ uint256 takerZrxBalance; // Taker's balance of ZRX
+ uint256 takerZrxAllowance; // Taker's allowance of ZRX to ERC20Proxy
+ }
+
+ // solhint-disable var-name-mixedcase
+ IExchange internal EXCHANGE;
+ bytes internal ZRX_ASSET_DATA;
+ // solhint-enable var-name-mixedcase
+
+ constructor (address _exchange, bytes memory _zrxAssetData)
+ public
+ {
+ EXCHANGE = IExchange(_exchange);
+ ZRX_ASSET_DATA = _zrxAssetData;
+ }
+
+ /// @dev Fetches information for order and maker/taker of order.
+ /// @param order The order structure.
+ /// @param takerAddress Address that will be filling the order.
+ /// @return OrderInfo and TraderInfo instances for given order.
+ function getOrderAndTraderInfo(LibOrder.Order memory order, address takerAddress)
+ public
+ view
+ returns (LibOrder.OrderInfo memory orderInfo, TraderInfo memory traderInfo)
+ {
+ orderInfo = EXCHANGE.getOrderInfo(order);
+ traderInfo = getTraderInfo(order, takerAddress);
+ return (orderInfo, traderInfo);
+ }
+
+ /// @dev Fetches information for all passed in orders and the makers/takers of each order.
+ /// @param orders Array of order specifications.
+ /// @param takerAddresses Array of taker addresses corresponding to each order.
+ /// @return Arrays of OrderInfo and TraderInfo instances that correspond to each order.
+ function getOrdersAndTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
+ public
+ view
+ returns (LibOrder.OrderInfo[] memory ordersInfo, TraderInfo[] memory tradersInfo)
+ {
+ ordersInfo = EXCHANGE.getOrdersInfo(orders);
+ tradersInfo = getTradersInfo(orders, takerAddresses);
+ return (ordersInfo, tradersInfo);
+ }
+
+ /// @dev Fetches balance and allowances for maker and taker of order.
+ /// @param order The order structure.
+ /// @param takerAddress Address that will be filling the order.
+ /// @return Balances and allowances of maker and taker of order.
+ function getTraderInfo(LibOrder.Order memory order, address takerAddress)
+ public
+ view
+ returns (TraderInfo memory traderInfo)
+ {
+ (traderInfo.makerBalance, traderInfo.makerAllowance) = getBalanceAndAllowance(order.makerAddress, order.makerAssetData);
+ (traderInfo.takerBalance, traderInfo.takerAllowance) = getBalanceAndAllowance(takerAddress, order.takerAssetData);
+ bytes memory zrxAssetData = ZRX_ASSET_DATA;
+ (traderInfo.makerZrxBalance, traderInfo.makerZrxAllowance) = getBalanceAndAllowance(order.makerAddress, zrxAssetData);
+ (traderInfo.takerZrxBalance, traderInfo.takerZrxAllowance) = getBalanceAndAllowance(takerAddress, zrxAssetData);
+ return traderInfo;
+ }
+
+ /// @dev Fetches balances and allowances of maker and taker for each provided order.
+ /// @param orders Array of order specifications.
+ /// @param takerAddresses Array of taker addresses corresponding to each order.
+ /// @return Array of balances and allowances for maker and taker of each order.
+ function getTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
+ public
+ view
+ returns (TraderInfo[] memory)
+ {
+ uint256 ordersLength = orders.length;
+ TraderInfo[] memory tradersInfo = new TraderInfo[](ordersLength);
+ for (uint256 i = 0; i != ordersLength; i++) {
+ tradersInfo[i] = getTraderInfo(orders[i], takerAddresses[i]);
+ }
+ return tradersInfo;
+ }
+
+ /// @dev Fetches token balances and allowances of an address to given assetProxy. Supports ERC20 and ERC721.
+ /// @param target Address to fetch balances and allowances of.
+ /// @param assetData Encoded data that can be decoded by a specified proxy contract when transferring asset.
+ /// @return Balance of asset and allowance set to given proxy of asset.
+ /// For ERC721 tokens, these values will always be 1 or 0.
+ function getBalanceAndAllowance(address target, bytes memory assetData)
+ public
+ view
+ returns (uint256 balance, uint256 allowance)
+ {
+ bytes4 assetProxyId = assetData.readBytes4(0);
+ address token = assetData.readAddress(16);
+ address assetProxy = EXCHANGE.getAssetProxy(assetProxyId);
+
+ if (assetProxyId == ERC20_DATA_ID) {
+ // Query balance
+ balance = IERC20Token(token).balanceOf(target);
+
+ // Query allowance
+ allowance = IERC20Token(token).allowance(target, assetProxy);
+ } else if (assetProxyId == ERC721_DATA_ID) {
+ uint256 tokenId = assetData.readUint256(36);
+
+ // Query owner of tokenId
+ address owner = getERC721TokenOwner(token, tokenId);
+
+ // Set balance to 1 if tokenId is owned by target
+ balance = target == owner ? 1 : 0;
+
+ // Check if ERC721Proxy is approved to spend tokenId
+ bool isApproved = IERC721Token(token).isApprovedForAll(target, assetProxy) || IERC721Token(token).getApproved(tokenId) == assetProxy;
+
+ // Set alowance to 1 if ERC721Proxy is approved to spend tokenId
+ allowance = isApproved ? 1 : 0;
+ } else {
+ revert("UNSUPPORTED_ASSET_PROXY");
+ }
+ return (balance, allowance);
+ }
+
+ /// @dev Fetches token balances and allowances of an address for each given assetProxy. Supports ERC20 and ERC721.
+ /// @param target Address to fetch balances and allowances of.
+ /// @param assetData Array of encoded byte arrays that can be decoded by a specified proxy contract when transferring asset.
+ /// @return Balances and allowances of assets.
+ /// For ERC721 tokens, these values will always be 1 or 0.
+ function getBalancesAndAllowances(address target, bytes[] memory assetData)
+ public
+ view
+ returns (uint256[] memory, uint256[] memory)
+ {
+ uint256 length = assetData.length;
+ uint256[] memory balances = new uint256[](length);
+ uint256[] memory allowances = new uint256[](length);
+ for (uint256 i = 0; i != length; i++) {
+ (balances[i], allowances[i]) = getBalanceAndAllowance(target, assetData[i]);
+ }
+ return (balances, allowances);
+ }
+
+ /// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
+ /// @param token Address of ERC721 token.
+ /// @param tokenId The identifier for the specific NFT.
+ /// @return Owner of tokenId or null address if unowned.
+ function getERC721TokenOwner(address token, uint256 tokenId)
+ public
+ view
+ returns (address owner)
+ {
+ assembly {
+ // load free memory pointer
+ let cdStart := mload(64)
+
+ // bytes4(keccak256(ownerOf(uint256))) = 0x6352211e
+ mstore(cdStart, 0x6352211e00000000000000000000000000000000000000000000000000000000)
+ mstore(add(cdStart, 4), tokenId)
+
+ // staticcall `ownerOf(tokenId)`
+ // `ownerOf` will revert if tokenId is not owned
+ let success := staticcall(
+ gas, // forward all gas
+ token, // call token contract
+ cdStart, // start of calldata
+ 36, // length of input is 36 bytes
+ cdStart, // write output over input
+ 32 // size of output is 32 bytes
+ )
+
+ // Success implies that tokenId is owned
+ // Copy owner from return data if successful
+ if success {
+ owner := mload(cdStart)
+ }
+ }
+
+ // Owner initialized to address(0), no need to modify if call is unsuccessful
+ return owner;
+ }
+}