Merge pull request #1383 from 0xProject/feature/contracts/balanceThresholdFilter
Balance Threshold Filter
This commit is contained in:
commit
38346a9aae
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.1.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Added Balance Threshold Filter",
|
||||||
|
"pr": 1383
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1544741676,
|
"timestamp": 1544741676,
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -18,5 +18,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"contracts": ["DutchAuction", "Forwarder"]
|
"contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder"]
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
|
import "./interfaces/IThresholdAsset.sol";
|
||||||
|
import "./MixinBalanceThresholdFilterCore.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract BalanceThresholdFilter is
|
||||||
|
MixinBalanceThresholdFilterCore
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @dev Constructs BalanceThresholdFilter.
|
||||||
|
/// @param exchange Address of 0x exchange.
|
||||||
|
/// @param thresholdAsset The asset that must be held by makers/takers.
|
||||||
|
/// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers.
|
||||||
|
constructor(
|
||||||
|
address exchange,
|
||||||
|
address thresholdAsset,
|
||||||
|
uint256 balanceThreshold
|
||||||
|
)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
EXCHANGE = IExchange(exchange);
|
||||||
|
THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
|
||||||
|
BALANCE_THRESHOLD = balanceThreshold;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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/LICENSE2.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;
|
||||||
|
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibExchangeSelectors.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
|
import "./mixins/MBalanceThresholdFilterCore.sol";
|
||||||
|
import "./MixinExchangeCalldata.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinBalanceThresholdFilterCore is
|
||||||
|
MBalanceThresholdFilterCore,
|
||||||
|
MixinExchangeCalldata,
|
||||||
|
LibOrder,
|
||||||
|
LibExchangeSelectors
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @dev Executes an Exchange transaction iff the maker and taker meet
|
||||||
|
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
|
||||||
|
/// the exchange function is a cancellation.
|
||||||
|
/// Supported Exchange functions:
|
||||||
|
/// batchFillOrders
|
||||||
|
/// batchFillOrdersNoThrow
|
||||||
|
/// batchFillOrKillOrders
|
||||||
|
/// fillOrder
|
||||||
|
/// fillOrderNoThrow
|
||||||
|
/// fillOrKillOrder
|
||||||
|
/// marketBuyOrders
|
||||||
|
/// marketBuyOrdersNoThrow
|
||||||
|
/// marketSellOrders
|
||||||
|
/// marketSellOrdersNoThrow
|
||||||
|
/// matchOrders
|
||||||
|
/// cancelOrder
|
||||||
|
/// batchCancelOrders
|
||||||
|
/// cancelOrdersUpTo
|
||||||
|
/// Trying to call any other exchange function will throw.
|
||||||
|
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @param signedExchangeTransaction AbiV2 encoded calldata.
|
||||||
|
/// @param signature Proof of signer transaction by signer.
|
||||||
|
function executeTransaction(
|
||||||
|
uint256 salt,
|
||||||
|
address signerAddress,
|
||||||
|
bytes signedExchangeTransaction,
|
||||||
|
bytes signature
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
// Get accounts whose balances must be validated
|
||||||
|
address[] memory addressesToValidate = getAddressesToValidate(signerAddress);
|
||||||
|
|
||||||
|
// Validate account balances
|
||||||
|
uint256 balanceThreshold = BALANCE_THRESHOLD;
|
||||||
|
IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
|
||||||
|
for (uint256 i = 0; i < addressesToValidate.length; ++i) {
|
||||||
|
uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
|
||||||
|
require(
|
||||||
|
addressBalance >= balanceThreshold,
|
||||||
|
"AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
emit ValidatedAddresses(addressesToValidate);
|
||||||
|
|
||||||
|
// All addresses are valid. Execute exchange function.
|
||||||
|
EXCHANGE.executeTransaction(
|
||||||
|
salt,
|
||||||
|
signerAddress,
|
||||||
|
signedExchangeTransaction,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Constructs an array of addresses to be validated.
|
||||||
|
/// Addresses depend on which Exchange function is to be called
|
||||||
|
/// (defined by `signedExchangeTransaction` above).
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @return addressesToValidate Array of addresses to validate.
|
||||||
|
function getAddressesToValidate(address signerAddress)
|
||||||
|
internal pure
|
||||||
|
returns (address[] memory addressesToValidate)
|
||||||
|
{
|
||||||
|
bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
|
||||||
|
// solhint-disable expression-indent
|
||||||
|
if (
|
||||||
|
exchangeFunctionSelector == BATCH_FILL_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_BUY_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_SELL_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||||
|
) {
|
||||||
|
addressesToValidate = loadMakerAddressesFromOrderArray(0);
|
||||||
|
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||||
|
} else if (
|
||||||
|
exchangeFunctionSelector == FILL_ORDER_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR
|
||||||
|
) {
|
||||||
|
address makerAddress = loadMakerAddressFromOrder(0);
|
||||||
|
addressesToValidate = addressesToValidate.append(makerAddress);
|
||||||
|
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||||
|
} else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) {
|
||||||
|
address leftMakerAddress = loadMakerAddressFromOrder(0);
|
||||||
|
addressesToValidate = addressesToValidate.append(leftMakerAddress);
|
||||||
|
address rightMakerAddress = loadMakerAddressFromOrder(1);
|
||||||
|
addressesToValidate = addressesToValidate.append(rightMakerAddress);
|
||||||
|
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||||
|
} else if (
|
||||||
|
exchangeFunctionSelector != CANCEL_ORDER_SELECTOR &&
|
||||||
|
exchangeFunctionSelector != BATCH_CANCEL_ORDERS_SELECTOR &&
|
||||||
|
exchangeFunctionSelector != CANCEL_ORDERS_UP_TO_SELECTOR
|
||||||
|
) {
|
||||||
|
revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
|
||||||
|
}
|
||||||
|
// solhint-enable expression-indent
|
||||||
|
return addressesToValidate;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
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/LICENSE2.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;
|
||||||
|
|
||||||
|
import "./mixins/MExchangeCalldata.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinExchangeCalldata is
|
||||||
|
MExchangeCalldata
|
||||||
|
{
|
||||||
|
|
||||||
|
using LibAddressArray for address[];
|
||||||
|
|
||||||
|
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
|
||||||
|
/// which is accessed through `signedExchangeTransaction`.
|
||||||
|
/// @param offset Offset into the Exchange calldata.
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset`.
|
||||||
|
function exchangeCalldataload(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value)
|
||||||
|
{
|
||||||
|
assembly {
|
||||||
|
// Pointer to exchange transaction
|
||||||
|
// 0x04 for calldata selector
|
||||||
|
// 0x40 to access `signedExchangeTransaction`, which is the third parameter
|
||||||
|
let exchangeTxPtr := calldataload(0x44)
|
||||||
|
|
||||||
|
// Offset into Exchange calldata
|
||||||
|
// We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
|
||||||
|
// 0x04 for calldata selector
|
||||||
|
// 0x20 for length field of `signedExchangeTransaction`
|
||||||
|
let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
|
||||||
|
value := calldataload(exchangeCalldataOffset)
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Convenience function that skips the 4 byte selector when loading
|
||||||
|
/// from the embedded Exchange calldata.
|
||||||
|
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset` + 4.
|
||||||
|
function loadExchangeData(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value)
|
||||||
|
{
|
||||||
|
value = exchangeCalldataload(offset + 4);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Extracts the maker address from an order stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderParamIndex Index of the order in the Exchange function's signature.
|
||||||
|
/// @return makerAddress The extracted maker address.
|
||||||
|
function loadMakerAddressFromOrder(uint256 orderParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address makerAddress)
|
||||||
|
{
|
||||||
|
uint256 orderOffsetInBytes = orderParamIndex * 32;
|
||||||
|
uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes));
|
||||||
|
makerAddress = address(loadExchangeData(orderPtr));
|
||||||
|
return makerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
|
||||||
|
/// @return makerAddresses The extracted maker addresses.
|
||||||
|
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address[] makerAddresses)
|
||||||
|
{
|
||||||
|
uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
|
||||||
|
uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes));
|
||||||
|
uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
|
||||||
|
uint256 orderArrayLengthInBytes = orderArrayLength * 32;
|
||||||
|
uint256 orderArrayElementPtr = orderArrayPtr + 32;
|
||||||
|
uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
|
||||||
|
for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
|
||||||
|
uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
|
||||||
|
address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
|
||||||
|
makerAddresses = makerAddresses.append(makerAddress);
|
||||||
|
}
|
||||||
|
return makerAddresses;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
contract IBalanceThresholdFilterCore {
|
||||||
|
|
||||||
|
/// @dev Executes an Exchange transaction iff the maker and taker meet
|
||||||
|
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
|
||||||
|
/// the exchange function is a cancellation.
|
||||||
|
/// Supported Exchange functions:
|
||||||
|
/// - batchFillOrders
|
||||||
|
/// - batchFillOrdersNoThrow
|
||||||
|
/// - batchFillOrKillOrders
|
||||||
|
/// - fillOrder
|
||||||
|
/// - fillOrderNoThrow
|
||||||
|
/// - fillOrKillOrder
|
||||||
|
/// - marketBuyOrders
|
||||||
|
/// - marketBuyOrdersNoThrow
|
||||||
|
/// - marketSellOrders
|
||||||
|
/// - marketSellOrdersNoThrow
|
||||||
|
/// - matchOrders
|
||||||
|
/// - cancelOrder
|
||||||
|
/// - batchCancelOrders
|
||||||
|
/// - cancelOrdersUpTo
|
||||||
|
/// Trying to call any other exchange function will throw.
|
||||||
|
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @param signedExchangeTransaction AbiV2 encoded calldata.
|
||||||
|
/// @param signature Proof of signer transaction by signer.
|
||||||
|
function executeTransaction(
|
||||||
|
uint256 salt,
|
||||||
|
address signerAddress,
|
||||||
|
bytes signedExchangeTransaction,
|
||||||
|
bytes signature
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
contract IThresholdAsset {
|
||||||
|
|
||||||
|
/// @param _owner The address from which the balance will be retrieved
|
||||||
|
/// @return Balance of owner
|
||||||
|
function balanceOf(address _owner)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
|
import "../interfaces/IThresholdAsset.sol";
|
||||||
|
import "../interfaces/IBalanceThresholdFilterCore.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MBalanceThresholdFilterCore is
|
||||||
|
IBalanceThresholdFilterCore
|
||||||
|
{
|
||||||
|
|
||||||
|
// Points to 0x exchange contract
|
||||||
|
// solhint-disable var-name-mixedcase
|
||||||
|
IExchange internal EXCHANGE;
|
||||||
|
|
||||||
|
// The asset that must be held by makers/takers
|
||||||
|
IThresholdAsset internal THRESHOLD_ASSET;
|
||||||
|
|
||||||
|
// The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
|
||||||
|
uint256 internal BALANCE_THRESHOLD;
|
||||||
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
|
// Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET`
|
||||||
|
event ValidatedAddresses (
|
||||||
|
address[] addresses
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Constructs an array of addresses to be validated.
|
||||||
|
/// Addresses depend on which Exchange function is to be called
|
||||||
|
/// (defined by `signedExchangeTransaction` above).
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @return addressesToValidate Array of addresses to validate.
|
||||||
|
function getAddressesToValidate(address signerAddress)
|
||||||
|
internal pure
|
||||||
|
returns (address[] memory addressesToValidate);
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
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/LICENSE2.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;
|
||||||
|
|
||||||
|
|
||||||
|
contract MExchangeCalldata {
|
||||||
|
|
||||||
|
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
|
||||||
|
/// which is accessed through `signedExchangeTransaction`.
|
||||||
|
/// @param offset Offset into the Exchange calldata.
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset`.
|
||||||
|
function exchangeCalldataload(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value);
|
||||||
|
|
||||||
|
/// @dev Convenience function that skips the 4 byte selector when loading
|
||||||
|
/// from the embedded Exchange calldata.
|
||||||
|
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset` + 4.
|
||||||
|
function loadExchangeData(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value);
|
||||||
|
|
||||||
|
/// @dev Extracts the maker address from an order stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderParamIndex Index of the order in the Exchange function's signature.
|
||||||
|
/// @return makerAddress The extracted maker address.
|
||||||
|
function loadMakerAddressFromOrder(uint256 orderParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address makerAddress);
|
||||||
|
|
||||||
|
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
|
||||||
|
/// @return makerAddresses The extracted maker addresses.
|
||||||
|
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address[] makerAddresses);
|
||||||
|
}
|
@ -31,7 +31,7 @@
|
|||||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"abis": "generated-artifacts/@(DutchAuction|Forwarder).json"
|
"abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder).json"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { ContractArtifact } from 'ethereum-types';
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
|
||||||
import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
|
import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
|
||||||
import * as Forwarder from '../../generated-artifacts/Forwarder.json';
|
import * as Forwarder from '../../generated-artifacts/Forwarder.json';
|
||||||
|
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
|
BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
|
||||||
DutchAuction: DutchAuction as ContractArtifact,
|
DutchAuction: DutchAuction as ContractArtifact,
|
||||||
Forwarder: Forwarder as ContractArtifact,
|
Forwarder: Forwarder as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
|
export * from '../../generated-wrappers/balance_threshold_filter';
|
||||||
export * from '../../generated-wrappers/dutch_auction';
|
export * from '../../generated-wrappers/dutch_auction';
|
||||||
export * from '../../generated-wrappers/forwarder';
|
export * from '../../generated-wrappers/forwarder';
|
||||||
|
1644
contracts/extensions/test/extensions/balance_threshold_filter.ts
Normal file
1644
contracts/extensions/test/extensions/balance_threshold_filter.ts
Normal file
File diff suppressed because it is too large
Load Diff
283
contracts/extensions/test/utils/balance_threshold_wrapper.ts
Normal file
283
contracts/extensions/test/utils/balance_threshold_wrapper.ts
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol';
|
||||||
|
import {
|
||||||
|
FillResults,
|
||||||
|
formatters,
|
||||||
|
LogDecoder,
|
||||||
|
OrderInfo,
|
||||||
|
orderUtils,
|
||||||
|
TransactionFactory,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
|
||||||
|
import { SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
|
||||||
|
import { artifacts } from '../../src/artifacts';
|
||||||
|
|
||||||
|
export class BalanceThresholdWrapper {
|
||||||
|
private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
|
||||||
|
private readonly _signerTransactionFactory: TransactionFactory;
|
||||||
|
private readonly _exchange: ExchangeContract;
|
||||||
|
private readonly _web3Wrapper: Web3Wrapper;
|
||||||
|
private readonly _logDecoder: LogDecoder;
|
||||||
|
constructor(
|
||||||
|
balanceThresholdFilter: BalanceThresholdFilterContract,
|
||||||
|
exchangeContract: ExchangeContract,
|
||||||
|
signerTransactionFactory: TransactionFactory,
|
||||||
|
provider: Provider,
|
||||||
|
) {
|
||||||
|
this._balanceThresholdFilter = balanceThresholdFilter;
|
||||||
|
this._exchange = exchangeContract;
|
||||||
|
this._signerTransactionFactory = signerTransactionFactory;
|
||||||
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
|
this._logDecoder = new LogDecoder(this._web3Wrapper, {
|
||||||
|
...artifacts,
|
||||||
|
...tokensArtifacts,
|
||||||
|
...protocolArtifacts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public async fillOrderAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async fillOrKillOrderAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async fillOrderNoThrowAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrKillOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketSellOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount: BigNumber },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketSellOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketBuyOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { makerAssetFillAmount: BigNumber },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.makerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketBuyOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.makerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createCancel(signedOrder);
|
||||||
|
const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchCancelOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchCancel(orders);
|
||||||
|
const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
|
||||||
|
const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
|
||||||
|
return filledAmount;
|
||||||
|
}
|
||||||
|
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
|
||||||
|
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
|
||||||
|
const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
|
||||||
|
return orderEpoch;
|
||||||
|
}
|
||||||
|
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
|
||||||
|
const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
|
||||||
|
return orderInfo;
|
||||||
|
}
|
||||||
|
public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
|
||||||
|
const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
|
||||||
|
return ordersInfo;
|
||||||
|
}
|
||||||
|
public async matchOrdersAsync(
|
||||||
|
signedOrderLeft: SignedOrder,
|
||||||
|
signedOrderRight: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
|
const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
params.left,
|
||||||
|
params.right,
|
||||||
|
params.leftSignature,
|
||||||
|
params.rightSignature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async getFillOrderResultsAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<FillResults> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const fillResults = await this._exchange.fillOrder.callAsync(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
{ from },
|
||||||
|
);
|
||||||
|
return fillResults;
|
||||||
|
}
|
||||||
|
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
public getBalanceThresholdAddress(): string {
|
||||||
|
return this._balanceThresholdFilter.address;
|
||||||
|
}
|
||||||
|
public getExchangeAddress(): string {
|
||||||
|
return this._exchange.address;
|
||||||
|
}
|
||||||
|
private async _executeTransactionAsync(
|
||||||
|
abiEncodedExchangeTxData: string,
|
||||||
|
from: string,
|
||||||
|
gas?: number,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
|
||||||
|
const txOpts = _.isUndefined(gas) ? { from } : { from, gas };
|
||||||
|
const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
|
||||||
|
signedExchangeTx.salt,
|
||||||
|
signedExchangeTx.signerAddress,
|
||||||
|
signedExchangeTx.data,
|
||||||
|
signedExchangeTx.signature,
|
||||||
|
txOpts,
|
||||||
|
);
|
||||||
|
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,10 @@
|
|||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
"files": ["./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"],
|
"files": [
|
||||||
|
"./generated-artifacts/BalanceThresholdFilter.json",
|
||||||
|
"./generated-artifacts/DutchAuction.json",
|
||||||
|
"./generated-artifacts/Forwarder.json"
|
||||||
|
],
|
||||||
"exclude": ["./deploy/solc/solc_bin"]
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
}
|
}
|
||||||
|
84
contracts/libs/contracts/libs/LibAddressArray.sol
Normal file
84
contracts/libs/contracts/libs/LibAddressArray.sol
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
|
|
||||||
|
|
||||||
|
library LibAddressArray {
|
||||||
|
|
||||||
|
/// @dev Append a new address to an array of addresses.
|
||||||
|
/// The `addressArray` may need to be reallocated to make space
|
||||||
|
/// for the new address. Because of this we return the resulting
|
||||||
|
/// memory location of `addressArray`.
|
||||||
|
/// @param addressToAppend Address to append.
|
||||||
|
/// @return Array of addresses: [... addressArray, addressToAppend]
|
||||||
|
function append(address[] memory addressArray, address addressToAppend)
|
||||||
|
internal pure
|
||||||
|
returns (address[])
|
||||||
|
{
|
||||||
|
// Get stats on address array and free memory
|
||||||
|
uint256 freeMemPtr = 0;
|
||||||
|
uint256 addressArrayBeginPtr = 0;
|
||||||
|
uint256 addressArrayEndPtr = 0;
|
||||||
|
uint256 addressArrayLength = addressArray.length;
|
||||||
|
uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);
|
||||||
|
assembly {
|
||||||
|
freeMemPtr := mload(0x40)
|
||||||
|
addressArrayBeginPtr := addressArray
|
||||||
|
addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cases for `freeMemPtr`:
|
||||||
|
// `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`
|
||||||
|
// `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`
|
||||||
|
// `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.
|
||||||
|
require(
|
||||||
|
freeMemPtr >= addressArrayEndPtr,
|
||||||
|
"INVALID_FREE_MEMORY_PTR"
|
||||||
|
);
|
||||||
|
|
||||||
|
// If free memory begins at the end of `addressArray`
|
||||||
|
// then we can append `addressToAppend` directly.
|
||||||
|
// Otherwise, we must copy the array to free memory
|
||||||
|
// before appending new values to it.
|
||||||
|
if (freeMemPtr > addressArrayEndPtr) {
|
||||||
|
LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);
|
||||||
|
assembly {
|
||||||
|
addressArray := freeMemPtr
|
||||||
|
addressArrayBeginPtr := addressArray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append `addressToAppend`
|
||||||
|
addressArrayLength += 1;
|
||||||
|
addressArrayMemSizeInBytes += 32;
|
||||||
|
addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;
|
||||||
|
freeMemPtr = addressArrayEndPtr;
|
||||||
|
assembly {
|
||||||
|
// Store new array length
|
||||||
|
mstore(addressArray, addressArrayLength)
|
||||||
|
|
||||||
|
// Update `freeMemPtr`
|
||||||
|
mstore(0x40, freeMemPtr)
|
||||||
|
}
|
||||||
|
addressArray[addressArrayLength - 1] = addressToAppend;
|
||||||
|
return addressArray;
|
||||||
|
}
|
||||||
|
}
|
152
contracts/libs/contracts/libs/LibExchangeSelectors.sol
Normal file
152
contracts/libs/contracts/libs/LibExchangeSelectors.sol
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
contract LibExchangeSelectors {
|
||||||
|
|
||||||
|
// solhint-disable max-line-length
|
||||||
|
// allowedValidators
|
||||||
|
bytes4 constant public ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;
|
||||||
|
bytes4 constant public ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256("allowedValidators(address,address)"));
|
||||||
|
|
||||||
|
// assetProxies
|
||||||
|
bytes4 constant public ASSET_PROXIES_SELECTOR = 0x3fd3c997;
|
||||||
|
bytes4 constant public ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256("assetProxies(bytes4)"));
|
||||||
|
|
||||||
|
// batchCancelOrders
|
||||||
|
bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;
|
||||||
|
bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])"));
|
||||||
|
|
||||||
|
// batchFillOrKillOrders
|
||||||
|
bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;
|
||||||
|
bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
|
||||||
|
|
||||||
|
// batchFillOrders
|
||||||
|
bytes4 constant public BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;
|
||||||
|
bytes4 constant public BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
|
||||||
|
|
||||||
|
// batchFillOrdersNoThrow
|
||||||
|
bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;
|
||||||
|
bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
|
||||||
|
|
||||||
|
// cancelOrder
|
||||||
|
bytes4 constant public CANCEL_ORDER_SELECTOR = 0xd46b02c3;
|
||||||
|
bytes4 constant public CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))"));
|
||||||
|
|
||||||
|
// cancelOrdersUpTo
|
||||||
|
bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;
|
||||||
|
bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrdersUpTo(uint256)"));
|
||||||
|
|
||||||
|
// cancelled
|
||||||
|
bytes4 constant public CANCELLED_SELECTOR = 0x2ac12622;
|
||||||
|
bytes4 constant public CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256("cancelled(bytes32)"));
|
||||||
|
|
||||||
|
// currentContextAddress
|
||||||
|
bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;
|
||||||
|
bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256("currentContextAddress()"));
|
||||||
|
|
||||||
|
// executeTransaction
|
||||||
|
bytes4 constant public EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;
|
||||||
|
bytes4 constant public EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256("executeTransaction(uint256,address,bytes,bytes)"));
|
||||||
|
|
||||||
|
// fillOrKillOrder
|
||||||
|
bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;
|
||||||
|
bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
|
||||||
|
|
||||||
|
// fillOrder
|
||||||
|
bytes4 constant public FILL_ORDER_SELECTOR = 0xb4be83d5;
|
||||||
|
bytes4 constant public FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
|
||||||
|
|
||||||
|
// fillOrderNoThrow
|
||||||
|
bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;
|
||||||
|
bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
|
||||||
|
|
||||||
|
// filled
|
||||||
|
bytes4 constant public FILLED_SELECTOR = 0x288cdc91;
|
||||||
|
bytes4 constant public FILLED_SELECTOR_GENERATOR = bytes4(keccak256("filled(bytes32)"));
|
||||||
|
|
||||||
|
// getAssetProxy
|
||||||
|
bytes4 constant public GET_ASSET_PROXY_SELECTOR = 0x60704108;
|
||||||
|
bytes4 constant public GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("getAssetProxy(bytes4)"));
|
||||||
|
|
||||||
|
// getOrderInfo
|
||||||
|
bytes4 constant public GET_ORDER_INFO_SELECTOR = 0xc75e0a81;
|
||||||
|
bytes4 constant public GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))"));
|
||||||
|
|
||||||
|
// getOrdersInfo
|
||||||
|
bytes4 constant public GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;
|
||||||
|
bytes4 constant public GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])"));
|
||||||
|
|
||||||
|
// isValidSignature
|
||||||
|
bytes4 constant public IS_VALID_SIGNATURE_SELECTOR = 0x93634702;
|
||||||
|
bytes4 constant public IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256("isValidSignature(bytes32,address,bytes)"));
|
||||||
|
|
||||||
|
// marketBuyOrders
|
||||||
|
bytes4 constant public MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;
|
||||||
|
bytes4 constant public MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
|
||||||
|
|
||||||
|
// marketBuyOrdersNoThrow
|
||||||
|
bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;
|
||||||
|
bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
|
||||||
|
|
||||||
|
// marketSellOrders
|
||||||
|
bytes4 constant public MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;
|
||||||
|
bytes4 constant public MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
|
||||||
|
|
||||||
|
// marketSellOrdersNoThrow
|
||||||
|
bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;
|
||||||
|
bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
|
||||||
|
|
||||||
|
// matchOrders
|
||||||
|
bytes4 constant public MATCH_ORDERS_SELECTOR = 0x3c28d861;
|
||||||
|
bytes4 constant public MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)"));
|
||||||
|
|
||||||
|
// orderEpoch
|
||||||
|
bytes4 constant public ORDER_EPOCH_SELECTOR = 0xd9bfa73e;
|
||||||
|
bytes4 constant public ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256("orderEpoch(address,address)"));
|
||||||
|
|
||||||
|
// owner
|
||||||
|
bytes4 constant public OWNER_SELECTOR = 0x8da5cb5b;
|
||||||
|
bytes4 constant public OWNER_SELECTOR_GENERATOR = bytes4(keccak256("owner()"));
|
||||||
|
|
||||||
|
// preSign
|
||||||
|
bytes4 constant public PRE_SIGN_SELECTOR = 0x3683ef8e;
|
||||||
|
bytes4 constant public PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256("preSign(bytes32,address,bytes)"));
|
||||||
|
|
||||||
|
// preSigned
|
||||||
|
bytes4 constant public PRE_SIGNED_SELECTOR = 0x82c174d0;
|
||||||
|
bytes4 constant public PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256("preSigned(bytes32,address)"));
|
||||||
|
|
||||||
|
// registerAssetProxy
|
||||||
|
bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;
|
||||||
|
bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("registerAssetProxy(address)"));
|
||||||
|
|
||||||
|
// setSignatureValidatorApproval
|
||||||
|
bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;
|
||||||
|
bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256("setSignatureValidatorApproval(address,bool)"));
|
||||||
|
|
||||||
|
// transactions
|
||||||
|
bytes4 constant public TRANSACTIONS_SELECTOR = 0x642f2eaf;
|
||||||
|
bytes4 constant public TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256("transactions(bytes32)"));
|
||||||
|
|
||||||
|
// transferOwnership
|
||||||
|
bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;
|
||||||
|
bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256("transferOwnership(address)"));
|
||||||
|
}
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.2.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Added LibAddressArray",
|
||||||
|
"pr": 1383
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1544741676,
|
"timestamp": 1544741676,
|
||||||
"version": "2.1.59",
|
"version": "2.1.59",
|
||||||
|
@ -104,6 +104,7 @@ export enum ContractName {
|
|||||||
Authorizable = 'Authorizable',
|
Authorizable = 'Authorizable',
|
||||||
Whitelist = 'Whitelist',
|
Whitelist = 'Whitelist',
|
||||||
Forwarder = 'Forwarder',
|
Forwarder = 'Forwarder',
|
||||||
|
BalanceThresholdFilter = 'BalanceThresholdFilter',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SignedTransaction {
|
export interface SignedTransaction {
|
||||||
|
@ -243,6 +243,10 @@ export enum RevertReason {
|
|||||||
AuctionNotStarted = 'AUCTION_NOT_STARTED',
|
AuctionNotStarted = 'AUCTION_NOT_STARTED',
|
||||||
AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME',
|
AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME',
|
||||||
InvalidAssetData = 'INVALID_ASSET_DATA',
|
InvalidAssetData = 'INVALID_ASSET_DATA',
|
||||||
|
// Balance Threshold Filter
|
||||||
|
InvalidOrBlockedExchangeSelector = 'INVALID_OR_BLOCKED_EXCHANGE_SELECTOR',
|
||||||
|
BalanceQueryFailed = 'BALANCE_QUERY_FAILED',
|
||||||
|
AtLeastOneAddressDoesNotMeetBalanceThreshold = 'AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum StatusCodes {
|
export enum StatusCodes {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user