Implement TEC MVP

This commit is contained in:
Amir Bandeali 2019-01-23 19:54:45 -08:00
parent 9eafbbc0ae
commit 844e3d1934
24 changed files with 1175 additions and 0 deletions

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,32 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.2.3 - _January 17, 2019_
* Dependencies updated
## v1.2.2 - _January 15, 2019_
* Dependencies updated
## v1.2.1 - _January 11, 2019_
* Dependencies updated
## v1.2.0 - _January 9, 2019_
* Added Dutch Auction Wrapper (#1465)
## v1.1.0 - _Invalid date_
* Added Balance Threshold Filter (#1383)
* Add OrderMatcher (#1117)
* Add OrderValidator (#1464)
## v1.0.2 - _December 13, 2018_
* Dependencies updated

View File

@ -0,0 +1 @@
[]

73
contracts/tec/README.md Normal file
View File

@ -0,0 +1,73 @@
## Extensions
This package implements various extensions to the 0x protocol. Extension contracts can add various rules around how orders are settled while still getting the interoperability and security benefits of using the underlying 0x protocol contracts. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
## Installation
**Install**
```bash
npm install @0x/contracts-extensions --save
```
## Bug bounty
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0x/contracts-extensions yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-extensions yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@ -0,0 +1,22 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"compilerSettings": {
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
},
"contracts": ["TEC"]
}

View File

@ -0,0 +1,98 @@
/*
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.5.2;
import "@0x/contract-utils/contracts/src/LibBytes.sol";
contract MixinSignatureValidator {
using LibBytes for bytes;
/// @dev Recovers the address of a signer given a hash and signature.
/// @param hash Any 32 byte hash.
/// @param signature Proof that the hash has been signed by signer.
function getSignerAddress(bytes32 hash, bytes memory signature)
internal
pure
returns (address signerAddress)
{
require(
signature.length > 0,
"LENGTH_GREATER_THAN_0_REQUIRED"
);
// Pop last byte off of signature byte array.
uint8 signatureTypeRaw = uint8(signature.popLastByte());
// Ensure signature is supported
require(
signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
"SIGNATURE_UNSUPPORTED"
);
SignatureType signatureType = SignatureType(signatureTypeRaw);
// Always illegal signature.
// This is always an implicit option since a signer can create a
// signature array with invalid type or length. We may as well make
// it an explicit option. This aids testing and analysis. It is
// also the initialization value for the enum type.
if (signatureType == SignatureType.Illegal) {
revert("SIGNATURE_ILLEGAL");
// Signature using EIP712
} else if (signatureType == SignatureType.EIP712) {
require(
signature.length == 65,
"LENGTH_65_REQUIRED"
);
uint8 v = uint8(signature[0]);
bytes32 r = signature.readBytes32(1);
bytes32 s = signature.readBytes32(33);
signerAddress = ecrecover(
hash,
v,
r,
s
);
return signerAddress;
// Signed using web3.eth_sign
} else if (signatureType == SignatureType.EthSign) {
require(
signature.length == 65,
"LENGTH_65_REQUIRED"
);
uint8 v = uint8(signature[0]);
bytes32 r = signature.readBytes32(1);
bytes32 s = signature.readBytes32(33);
signerAddress = ecrecover(
keccak256(abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
hash
)),
v,
r,
s
);
return signerAddress;
}
}
}

View File

@ -0,0 +1,232 @@
/*
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.5.2;
pragma experimental "ABIEncoderV2";
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "./libs/LibTECApproval.sol";
import "./libs/LibZeroExTransaction.sol";
import "./mixins/MSignatureValidator.sol";
import "./mixins/MTECApprovalVerifier.sol";
contract MixinTECApprovalVerifier is
LibExchangeSelectors,
LibTECApproval,
LibZeroExTransaction,
MSignatureValidator,
MTECApprovalVerifier
{
using LibAddressArray for address[];
using LibBytes for bytes;
/// @dev Validates that the 0x transaction has been approved by all of the feeRecipients
/// that correspond to each order in the transaction's Exchange calldata.
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
function assertValidTECApproval(
LibZeroExTransaction.ZeroExTransaction memory transaction,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
internal
view
{
// Hash 0x transaction
bytes32 transactionHash = getTransactionHash(transaction);
// Get the function selector of the Exchange calldata in the 0x transaction
bytes4 exchangeFunctionSelector = transaction.data.readBytes4(0);
if (
exchangeFunctionSelector == FILL_ORDER_SELECTOR ||
exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR ||
exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR ||
exchangeFunctionSelector == CANCEL_ORDER_SELECTOR
) {
// Decode single order
(LibOrder.Order memory order) = abi.decode(
transaction.data,
(LibOrder.Order)
);
// Revert if approval is invalid for single order
assertValidSingleOrderApproval(
order,
transactionHash,
transactionSignature,
approvalExpirationTimeSeconds[0],
approvalSignatures[0]
);
} else 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 ||
exchangeFunctionSelector == BATCH_CANCEL_ORDERS_SELECTOR
) {
// Decode all orders
(LibOrder.Order[] memory orders) = abi.decode(
transaction.data,
(LibOrder.Order[])
);
// Revert if approval is invalid for batch of orders
assertValidBatchOrderApproval(
orders,
transactionHash,
transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures
);
} else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) {
// Decode left and right orders
(LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(
transaction.data,
(LibOrder.Order, LibOrder.Order)
);
// Create array of orders
LibOrder.Order[] memory orders = new LibOrder.Order[](2);
orders[0] = leftOrder;
orders[1] = rightOrder;
// Revert if approval is invalid for batch of orders
assertValidBatchOrderApproval(
orders,
transactionHash,
transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures
);
} else if (exchangeFunctionSelector == CANCEL_ORDERS_UP_TO_SELECTOR) {
// `cancelOrdersUpTo` is always permitted
return;
} else {
revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
}
}
/// @dev Validates that the feeRecipient of a single order has approved a 0x transaction.
/// @param order Order struct containing order specifications.
/// @param transactionHash EIP712 hash of the 0x transaction.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Expiration times in seconds for which the approval signature expires.
/// @param approvalSignature Signatures that corresponds to the feeRecipient of the order.
function assertValidSingleOrderApproval(
LibOrder.Order memory order,
bytes32 transactionHash,
bytes memory transactionSignature,
uint256 approvalExpirationTimeSeconds,
bytes memory approvalSignature
)
internal
view
{
// Create approval message
TECApproval memory approval = TECApproval({
transactionHash: transactionHash,
transactionSignature: transactionSignature,
approvalExpirationTimeSeconds: approvalExpirationTimeSeconds
});
// Revert if approval expired
require(
// solhint-disable-next-line not-rely-on-time
approvalExpirationTimeSeconds > block.timestamp,
"APPROVAL_EXPIRED"
);
// Hash approval message and recover signer address
bytes32 approvalHash = getTECApprovalHash(approval);
address approvalSignerAddress = getAddressFromSignature(approvalHash, approvalSignature);
// Revert if signer of approval is not the feeRecipient of order
require(
order.feeRecipientAddress == approvalSignerAddress,
"INVALID_APPROVAL_SIGNATURE"
);
}
/// @dev Validates that the feeRecipient of a single order has approved a 0x transaction.
/// @param orders Array of order structs containing order specifications.
/// @param transactionHash EIP712 hash of the 0x transaction.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
function assertValidBatchOrderApproval(
LibOrder.Order[] memory orders,
bytes32 transactionHash,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
internal
view
{
// Create empty list of approval signers
address[] memory approvalSignerAddresses = new address[](0);
uint256 signaturesLength = approvalSignatures.length;
for (uint256 i = 0; i < signaturesLength; i++) {
// Create approval message
TECApproval memory approval = TECApproval({
transactionHash: transactionHash,
transactionSignature: transactionSignature,
approvalExpirationTimeSeconds: approvalExpirationTimeSeconds[i]
});
// Ensure approval has not expired
require(
// solhint-disable-next-line not-rely-on-time
approval.approvalExpirationTimeSeconds > block.timestamp,
"APPROVAL_EXPIRED"
);
// Hash approval message and recover signer address
bytes32 approvalHash = getTECApprovalHash(approval);
address approvalSignerAddress = getAddressFromSignature(approvalHash, approvalSignatures[i]);
// Add approval signer to list of signers
approvalSignerAddresses.append(approvalSignerAddress);
}
uint256 ordersLength = orders.length;
for (uint256 i = 0; i < ordersLength; i++) {
// Get index of feeRecipient in list of approval signers
(bool doesExist,) = approvalSignerAddresses.indexOf(orders[i].feeRecipientAddress);
// Ensure approval signer exists
require(
doesExist,
"INVALID_APPROVAL_SIGNATURE"
);
}
}
}

View File

@ -0,0 +1,62 @@
/*
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.5.2;
pragma experimental "ABIEncoderV2";
import "./libs/LibZeroExTransaction.sol";
import "./libs/LibConstants.sol";
import "./mixins/MTECApprovalVerifier.sol";
import "./interfaces/ITECCore.sol";
contract MixinTECCore is
LibConstants,
MTECApprovalVerifier,
ITECCore
{
/// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
function executeTransaction(
LibZeroExTransaction.ZeroExTransaction memory transaction,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
public
{
// Validate that the 0x transaction has been approves by each feeRecipient
assertValidTECApproval(
transaction,
transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures
);
// Execute the transaction
EXCHANGE.executeTransaction(
transaction.salt,
transaction.signerAddress,
transaction.data,
transactionSignature
);
}
}

View File

@ -0,0 +1,36 @@
/*
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.5.2;
import "./libs/LibConstants.sol";
import "./MixinTECApprovalVerifier.sol";
import "./MixinTECCore.sol";
// solhint-disable no-empty-blocks
contract TEC is
LibConstants,
MixinTECApprovalVerifier,
MixinTECCore
{
constructor (address _exchange)
public
LibConstants(_exchange)
{}
}

View File

@ -0,0 +1,35 @@
/*
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.5.2;
contract IExchange {
/// @dev Executes an exchange method call in the context of signer.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signerAddress Address of transaction signer.
/// @param data AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signerAddress,
bytes calldata data,
bytes calldata signature
)
external;
}

View File

@ -0,0 +1,39 @@
/*
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.5.2;
pragma experimental "ABIEncoderV2";
import "../libs/LibZeroExTransaction.sol";
contract ITECCore {
/// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
function executeTransaction(
LibZeroExTransaction.ZeroExTransaction memory transaction,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
public;
}

View File

@ -0,0 +1,34 @@
/*
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.5.2;
import "../interfaces/IExchange.sol";
contract LibConstants {
// solhint-disable-next-line var-name-mixedcase
IExchange internal EXCHANGE;
constructor (address _exchange)
public
{
EXCHANGE = IExchange(_exchange);
}
}

View File

@ -0,0 +1,87 @@
/*
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.5.2;
contract LibEIP712Domain {
// EIP191 header for EIP712 prefix
string constant internal EIP191_HEADER = "\x19\x01";
// EIP712 Domain Name value
string constant internal EIP712_DOMAIN_NAME = "0x Protocol Trade Execution Coordinator";
// EIP712 Domain Version value
string constant internal EIP712_DOMAIN_VERSION = "1.0.0";
// Hash of the EIP712 Domain Separator Schema
bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
"address verifyingContract",
")"
));
// Hash of the EIP712 Domain Separator data
// solhint-disable-next-line var-name-mixedcase
bytes32 public EIP712_DOMAIN_HASH;
constructor ()
public
{
EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
uint256(address(this))
));
}
/// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.
/// @param hashStruct The EIP712 hash struct.
/// @return EIP712 hash applied to this EIP712 Domain.
function hashEIP712Message(bytes32 hashStruct)
internal
view
returns (bytes32 result)
{
bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;
// Assembly for more efficient computing:
// keccak256(abi.encodePacked(
// EIP191_HEADER,
// EIP712_DOMAIN_HASH,
// hashStruct
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
mstore(add(memPtr, 34), hashStruct) // Hash of struct
// Compute hash
result := keccak256(memPtr, 66)
}
return result;
}
}

View File

@ -0,0 +1,89 @@
/*
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.5.2;
import "./LibEIP712Domain.sol";
contract LibTECApproval is
LibEIP712Domain
{
// Hash for the EIP712 TEC approval message
bytes32 constant internal EIP712_TEC_APPROVAL_SCHEMA_HASH = keccak256(abi.encodePacked(
"TECApproval(",
"bytes32 transactionHash,",
"bytes transactionSignature,",
"uint256 approvalExpirationTimeSeconds",
")"
));
struct TECApproval {
bytes32 transactionHash; // EIP712 hash of the transaction, using the domain separator of this contract.
bytes transactionSignature; // Signature of the 0x transaction.
uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the signature expires.
}
/// @dev Calculated the EIP712 hash of the TEC approval mesasage using the domain separator of this contract.
/// @param approval TEC approval message containing the transaction hash, transaction signature, and expiration of the approval.
/// @return EIP712 hash of the TEC approval message with the domain separator of this contract.
function getTECApprovalHash(TECApproval memory approval)
internal
view
returns (bytes32 approvalHash)
{
approvalHash = hashEIP712Message(hashTECApproval(approval));
return approvalHash;
}
/// @dev Calculated the EIP712 hash of the TEC approval mesasage with no domain separator.
/// @param approval TEC approval message containing the transaction hash, transaction signature, and expiration of the approval.
/// @return EIP712 hash of the TEC approval message with no domain separator.
function hashTECApproval(TECApproval memory approval)
internal
pure
returns (bytes32 result)
{
bytes32 schemaHash = EIP712_TEC_APPROVAL_SCHEMA_HASH;
bytes32 transactionSignatureHash = keccak256(approval.transactionSignature);
// TODO(abandeali1): optimize by loading from memory in assembly
bytes32 transactionHash = approval.transactionHash;
uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;
// Assembly for more efficiently computing:
// keccak256(abi.encodePacked(
// EIP712_TEC_APPROVAL_SCHEMA_HASH,
// approval.transactionHash,
// keccak256(approval.transactionSignature)
// approval.expiration,
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, schemaHash) // hash of schema
mstore(add(memPtr, 32), transactionHash) // transactionHash
mstore(add(memPtr, 64), transactionSignatureHash) // transactionSignatureHash
mstore(add(memPtr, 96), approvalExpirationTimeSeconds) // approvalExpirationTimeSeconds
// Compute hash
result := keccak256(memPtr, 128)
}
return result;
}
}

View File

@ -0,0 +1,91 @@
/*
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.5.2;
import "./LibEIP712Domain.sol";
contract LibZeroExTransaction is
LibEIP712Domain
{
// Hash for the EIP712 0x transaction schema
bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = keccak256(abi.encodePacked(
"ZeroExTransaction(",
"uint256 salt,",
"address signerAddress,",
"bytes data",
")"
));
struct ZeroExTransaction {
uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash.
address signerAddress; // Address of transaction signer.
bytes data; // AbiV2 encoded calldata.
}
/// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of this contract.
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @return EIP712 hash of the transaction with the domain separator of this contract.
function getTransactionHash(ZeroExTransaction memory transaction)
internal
view
returns (bytes32 transactionHash)
{
// Note: this transaction hash will differ from the hash produced by the Exchange contract because it utilizes a different domain hash.
transactionHash = hashEIP712Message(hashZeroExTransaction(transaction));
return transactionHash;
}
/// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @return EIP712 hash of the transaction with no domain separator.
function hashZeroExTransaction(ZeroExTransaction memory transaction)
internal
pure
returns (bytes32 result)
{
bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
bytes32 dataHash = keccak256(transaction.data);
// TODO(abandeali1): optimize by loading from memory in assembly
uint256 salt = transaction.salt;
address signerAddress = transaction.signerAddress;
// Assembly for more efficiently computing:
// keccak256(abi.encodePacked(
// EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
// transaction.salt,
// uint256(transaction.signerAddress),
// keccak256(transaction.data)
// ));
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, schemaHash) // hash of schema
mstore(add(memPtr, 32), salt) // salt
mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress
mstore(add(memPtr, 96), dataHash) // hash of data
// Compute hash
result := keccak256(memPtr, 128)
}
return result;
}
}

View File

@ -0,0 +1,39 @@
/*
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.5.2;
contract MSignatureValidator {
// Allowed signature types.
enum SignatureType {
Illegal, // 0x00, default value
EIP712, // 0x01
EthSign, // 0x02
NSignatureTypes // 0x03, number of signature types. Always leave at end.
}
/// @dev Recovers the address of a signer given a hash and signature.
/// @param hash Any 32 byte hash.
/// @param signature Proof that the hash has been signed by signer.
function getAddressFromSignature(bytes32 hash, bytes memory signature)
internal
pure
returns (address signerAddress);
}

View File

@ -0,0 +1,74 @@
/*
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.5.2;
pragma experimental "ABIEncoderV2";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "../libs/LibZeroExTransaction.sol";
contract MTECApprovalVerifier {
/// @dev Validates that the 0x transaction has been approved by all of the feeRecipients
/// that correspond to each order in the transaction's Exchange calldata.
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
function assertValidTECApproval(
LibZeroExTransaction.ZeroExTransaction memory transaction,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
internal
view;
/// @dev Validates that the feeRecipient of a single order has approved a 0x transaction.
/// @param order Order struct containing order specifications.
/// @param transactionHash EIP712 hash of the 0x transaction.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Expiration times in seconds for which the approval signature expires.
/// @param approvalSignature Signatures that corresponds to the feeRecipient of the order.
function assertValidSingleOrderApproval(
LibOrder.Order memory order,
bytes32 transactionHash,
bytes memory transactionSignature,
uint256 approvalExpirationTimeSeconds,
bytes memory approvalSignature
)
internal
view;
/// @dev Validates that the feeRecipient of a single order has approved a 0x transaction.
/// @param orders Array of order structs containing order specifications.
/// @param transactionHash EIP712 hash of the 0x transaction.
/// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
function assertValidBatchOrderApproval(
LibOrder.Order[] memory orders,
bytes32 transactionHash,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
internal
view;
}

View File

@ -0,0 +1,85 @@
{
"name": "@0x/contracts-tec",
"version": "0.0.1",
"engines": {
"node": ">=6.12"
},
"description": "Smart contract extensions of 0x protocol",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(TEC).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.22",
"@0x/contract-wrappers": "^5.0.1",
"@0x/contracts-test-utils": "^2.0.1",
"@0x/dev-utils": "^1.0.24",
"@0x/sol-compiler": "^2.0.2",
"@0x/tslint-config": "^2.0.2",
"@types/lodash": "4.14.104",
"@types/node": "*",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^3.0.13",
"@0x/contracts-exchange-libs": "^1.0.0",
"@0x/contracts-exchange": "^1.0.0",
"@0x/contracts-erc20": "^1.0.0",
"@0x/contracts-erc721": "^1.0.0",
"@0x/contracts-utils": "^3.0.0",
"@0x/order-utils": "^3.1.2",
"@0x/types": "^1.5.2",
"@0x/typescript-typings": "^3.0.8",
"@0x/utils": "^3.0.1",
"@0x/web3-wrapper": "^3.2.4",
"ethereum-types": "^1.1.6",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -0,0 +1,7 @@
import { ContractArtifact } from 'ethereum-types';
import * as TEC from '../../generated-artifacts/TEC.json';
export const artifacts = {
TEC: TEC as ContractArtifact,
};

View File

@ -0,0 +1,3 @@
export * from './artifacts';
export * from './wrappers';
// export * from '../test/utils';

View File

@ -0,0 +1 @@
export * from '../../generated-wrappers/tec';

View File

@ -0,0 +1,17 @@
import { env, EnvVars } from '@0x/dev-utils';
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
before('start web3 provider', () => {
provider.start();
});
after('generate coverage report', async () => {
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
await coverageSubprovider.writeCoverageAsync();
}
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
await profilerSubprovider.writeProfilerOutputAsync();
}
provider.stop();
});

View File

@ -0,0 +1,11 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": ["./generated-artifacts/TEC.json"],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@ -0,0 +1,6 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}