From b88ff0a19ff7695086107cbcffe980dc4ad84e10 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 10 Dec 2018 10:01:38 -0800 Subject: Refactor out examples --- .gitignore | 2 + .prettierignore | 2 + contracts/core/README.md | 2 - contracts/core/compiler.json | 6 +- .../examples/ExchangeWrapper/ExchangeWrapper.sol | 100 --------------- .../contracts/examples/Validator/Validator.sol | 56 --------- .../core/contracts/examples/Wallet/Wallet.sol | 65 ---------- .../contracts/examples/Whitelist/Whitelist.sol | 136 --------------------- contracts/core/package.json | 3 +- contracts/core/src/artifacts/index.ts | 8 -- contracts/core/src/wrappers/index.ts | 4 - contracts/core/tsconfig.json | 6 +- contracts/examples/.solhint.json | 20 +++ contracts/examples/README.md | 56 +++++++++ contracts/examples/compiler.json | 22 ++++ .../contracts/ExchangeWrapper/ExchangeWrapper.sol | 100 +++++++++++++++ .../examples/contracts/Validator/Validator.sol | 56 +++++++++ contracts/examples/contracts/Wallet/Wallet.sol | 65 ++++++++++ .../examples/contracts/Whitelist/Whitelist.sol | 136 +++++++++++++++++++++ contracts/examples/package.json | 83 +++++++++++++ contracts/examples/src/artifacts/index.ts | 13 ++ contracts/examples/src/index.ts | 2 + contracts/examples/src/wrappers/index.ts | 4 + contracts/examples/tsconfig.json | 16 +++ contracts/examples/tslint.json | 6 + 25 files changed, 587 insertions(+), 382 deletions(-) delete mode 100644 contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol delete mode 100644 contracts/core/contracts/examples/Validator/Validator.sol delete mode 100644 contracts/core/contracts/examples/Wallet/Wallet.sol delete mode 100644 contracts/core/contracts/examples/Whitelist/Whitelist.sol create mode 100644 contracts/examples/.solhint.json create mode 100644 contracts/examples/README.md create mode 100644 contracts/examples/compiler.json create mode 100644 contracts/examples/contracts/ExchangeWrapper/ExchangeWrapper.sol create mode 100644 contracts/examples/contracts/Validator/Validator.sol create mode 100644 contracts/examples/contracts/Wallet/Wallet.sol create mode 100644 contracts/examples/contracts/Whitelist/Whitelist.sol create mode 100644 contracts/examples/package.json create mode 100644 contracts/examples/src/artifacts/index.ts create mode 100644 contracts/examples/src/index.ts create mode 100644 contracts/examples/src/wrappers/index.ts create mode 100644 contracts/examples/tsconfig.json create mode 100644 contracts/examples/tslint.json diff --git a/.gitignore b/.gitignore index a49f2837b..26b077e86 100644 --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,7 @@ contracts/utils/generated-artifacts/ contracts/libs/generated-artifacts/ contracts/interfaces/generated-artifacts/ contracts/tokens/generated-artifacts/ +contracts/examples/generated-artifacts/ packages/sol-cov/test/fixtures/artifacts/ packages/metacoin/artifacts/ @@ -96,6 +97,7 @@ contracts/utils/generated-wrappers/ contracts/libs/generated-wrappers/ contracts/interfaces/generated-wrappers/ contracts/tokens/generated-wrappers/ +contracts/examples/generated-wrappers/ packages/metacoin/src/contract_wrappers # solc-bin in sol-compiler diff --git a/.prettierignore b/.prettierignore index 4da37ae6e..d50245827 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,6 +12,8 @@ lib /contracts/interfaces/generated-artifacts /contracts/tokens/generated-wrappers /contracts/tokens/generated-artifacts +/contracts/examples/generated-wrappers +/contracts/examples/generated-artifacts /packages/abi-gen-wrappers/src/generated-wrappers /packages/contract-artifacts/artifacts /python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts diff --git a/contracts/core/README.md b/contracts/core/README.md index 8371d8041..922ea21ad 100644 --- a/contracts/core/README.md +++ b/contracts/core/README.md @@ -10,8 +10,6 @@ Contracts that make up and interact with version 2.0.0 of the protocol can be fo * This directory contains the contracts that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md). * [extensions](./contracts/extensions) * This directory contains contracts that interact with the 2.0.0 contracts and will be used in production, such as the [Forwarder](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract. -* [examples](./contracts/examples) - * This directory contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others. * [test](./contracts/test) * This directory contains mocks and other contracts that are used solely for testing contracts within the other directories. diff --git a/contracts/core/compiler.json b/contracts/core/compiler.json index 606208e49..3f869024c 100644 --- a/contracts/core/compiler.json +++ b/contracts/core/compiler.json @@ -24,7 +24,6 @@ "ERC20Proxy", "ERC721Proxy", "Exchange", - "ExchangeWrapper", "Forwarder", "MixinAuthorizable", "MultiAssetProxy", @@ -33,9 +32,6 @@ "TestAssetProxyDispatcher", "TestExchangeInternals", "TestSignatureValidator", - "TestStaticCallReceiver", - "Validator", - "Wallet", - "Whitelist" + "TestStaticCallReceiver" ] } diff --git a/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol b/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol deleted file mode 100644 index d98136922..000000000 --- a/contracts/core/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol +++ /dev/null @@ -1,100 +0,0 @@ -/* - - 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 "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; -import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; - - -contract ExchangeWrapper { - - // Exchange contract. - // solhint-disable-next-line var-name-mixedcase - IExchange internal EXCHANGE; - - constructor (address _exchange) - public - { - EXCHANGE = IExchange(_exchange); - } - - /// @dev Cancels all orders created by sender with a salt less than or equal to the targetOrderEpoch - /// and senderAddress equal to this contract. - /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled. - /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash. - /// @param makerSignature Proof that maker wishes to call this function with given params. - function cancelOrdersUpTo( - uint256 targetOrderEpoch, - uint256 salt, - bytes makerSignature - ) - external - { - address makerAddress = msg.sender; - - // Encode arguments into byte array. - bytes memory data = abi.encodeWithSelector( - EXCHANGE.cancelOrdersUpTo.selector, - targetOrderEpoch - ); - - // Call `cancelOrdersUpTo` via `executeTransaction`. - EXCHANGE.executeTransaction( - salt, - makerAddress, - data, - makerSignature - ); - } - - /// @dev Fills an order using `msg.sender` as the taker. - /// @param order Order struct containing order specifications. - /// @param takerAssetFillAmount Desired amount of takerAsset to sell. - /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash. - /// @param orderSignature Proof that order has been created by maker. - /// @param takerSignature Proof that taker wishes to call this function with given params. - function fillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - uint256 salt, - bytes memory orderSignature, - bytes memory takerSignature - ) - public - { - address takerAddress = msg.sender; - - // Encode arguments into byte array. - bytes memory data = abi.encodeWithSelector( - EXCHANGE.fillOrder.selector, - order, - takerAssetFillAmount, - orderSignature - ); - - // Call `fillOrder` via `executeTransaction`. - EXCHANGE.executeTransaction( - salt, - takerAddress, - data, - takerSignature - ); - } -} diff --git a/contracts/core/contracts/examples/Validator/Validator.sol b/contracts/core/contracts/examples/Validator/Validator.sol deleted file mode 100644 index e488a9ca7..000000000 --- a/contracts/core/contracts/examples/Validator/Validator.sol +++ /dev/null @@ -1,56 +0,0 @@ -/* - - 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/IValidator.sol"; - - -contract Validator is - IValidator -{ - - // The single valid signer for this wallet. - // solhint-disable-next-line var-name-mixedcase - address internal VALID_SIGNER; - - /// @dev constructs a new `Validator` with a single valid signer. - /// @param validSigner The sole, valid signer. - constructor (address validSigner) public { - VALID_SIGNER = validSigner; - } - - /// @dev Verifies that a signature is valid. `signer` must match `VALID_SIGNER`. - /// @param hash Message hash that is signed. - /// @param signerAddress Address that should have signed the given hash. - /// @param signature Proof of signing. - /// @return Validity of signature. - // solhint-disable no-unused-vars - function isValidSignature( - bytes32 hash, - address signerAddress, - bytes signature - ) - external - view - returns (bool isValid) - { - return (signerAddress == VALID_SIGNER); - } - // solhint-enable no-unused-vars -} diff --git a/contracts/core/contracts/examples/Wallet/Wallet.sol b/contracts/core/contracts/examples/Wallet/Wallet.sol deleted file mode 100644 index 8edc74eb3..000000000 --- a/contracts/core/contracts/examples/Wallet/Wallet.sol +++ /dev/null @@ -1,65 +0,0 @@ -/* - - 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/IWallet.sol"; -import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; - - -contract Wallet is - IWallet -{ - using LibBytes for bytes; - - // The owner of this wallet. - // solhint-disable-next-line var-name-mixedcase - address internal WALLET_OWNER; - - /// @dev constructs a new `Wallet` with a single owner. - /// @param walletOwner The owner of this wallet. - constructor (address walletOwner) public { - WALLET_OWNER = walletOwner; - } - - /// @dev Validates an EIP712 signature. - /// The signer must match the owner of this wallet. - /// @param hash Message hash that is signed. - /// @param eip712Signature Proof of signing. - /// @return Validity of signature. - function isValidSignature( - bytes32 hash, - bytes eip712Signature - ) - external - view - returns (bool isValid) - { - require( - eip712Signature.length == 65, - "LENGTH_65_REQUIRED" - ); - - uint8 v = uint8(eip712Signature[0]); - bytes32 r = eip712Signature.readBytes32(1); - bytes32 s = eip712Signature.readBytes32(33); - address recoveredAddress = ecrecover(hash, v, r, s); - isValid = WALLET_OWNER == recoveredAddress; - return isValid; - } -} diff --git a/contracts/core/contracts/examples/Whitelist/Whitelist.sol b/contracts/core/contracts/examples/Whitelist/Whitelist.sol deleted file mode 100644 index 2a3d33738..000000000 --- a/contracts/core/contracts/examples/Whitelist/Whitelist.sol +++ /dev/null @@ -1,136 +0,0 @@ -/* - - 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 "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; -import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; -import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; - - -contract Whitelist is - Ownable -{ - - // Mapping of address => whitelist status. - mapping (address => bool) public isWhitelisted; - - // Exchange contract. - // solhint-disable var-name-mixedcase - IExchange internal EXCHANGE; - bytes internal TX_ORIGIN_SIGNATURE; - // solhint-enable var-name-mixedcase - - byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x05"; - - constructor (address _exchange) - public - { - EXCHANGE = IExchange(_exchange); - TX_ORIGIN_SIGNATURE = abi.encodePacked(address(this), VALIDATOR_SIGNATURE_BYTE); - } - - /// @dev Adds or removes an address from the whitelist. - /// @param target Address to add or remove from whitelist. - /// @param isApproved Whitelist status to assign to address. - function updateWhitelistStatus( - address target, - bool isApproved - ) - external - onlyOwner - { - isWhitelisted[target] = isApproved; - } - - /// @dev Verifies signer is same as signer of current Ethereum transaction. - /// NOTE: This function can currently be used to validate signatures coming from outside of this contract. - /// Extra safety checks can be added for a production contract. - /// @param signerAddress Address that should have signed the given hash. - /// @param signature Proof of signing. - /// @return Validity of order signature. - // solhint-disable no-unused-vars - function isValidSignature( - bytes32 hash, - address signerAddress, - bytes signature - ) - external - view - returns (bool isValid) - { - // solhint-disable-next-line avoid-tx-origin - return signerAddress == tx.origin; - } - // solhint-enable no-unused-vars - - /// @dev Fills an order using `msg.sender` as the taker. - /// The transaction will revert if both the maker and taker are not whitelisted. - /// Orders should specify this contract as the `senderAddress` in order to gaurantee - /// that both maker and taker have been whitelisted. - /// @param order Order struct containing order specifications. - /// @param takerAssetFillAmount Desired amount of takerAsset to sell. - /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash. - /// @param orderSignature Proof that order has been created by maker. - function fillOrderIfWhitelisted( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - uint256 salt, - bytes memory orderSignature - ) - public - { - address takerAddress = msg.sender; - - // This contract must be the entry point for the transaction. - require( - // solhint-disable-next-line avoid-tx-origin - takerAddress == tx.origin, - "INVALID_SENDER" - ); - - // Check if maker is on the whitelist. - require( - isWhitelisted[order.makerAddress], - "MAKER_NOT_WHITELISTED" - ); - - // Check if taker is on the whitelist. - require( - isWhitelisted[takerAddress], - "TAKER_NOT_WHITELISTED" - ); - - // Encode arguments into byte array. - bytes memory data = abi.encodeWithSelector( - EXCHANGE.fillOrder.selector, - order, - takerAssetFillAmount, - orderSignature - ); - - // Call `fillOrder` via `executeTransaction`. - EXCHANGE.executeTransaction( - salt, - takerAddress, - data, - TX_ORIGIN_SIGNATURE - ); - } -} diff --git a/contracts/core/package.json b/contracts/core/package.json index fd844ae16..62547c311 100644 --- a/contracts/core/package.json +++ b/contracts/core/package.json @@ -33,7 +33,7 @@ "lint-contracts": "solhint contracts/**/**/**/**/*.sol" }, "config": { - "abis": "generated-artifacts/@(AssetProxyOwner|DutchAuction|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|MixinAuthorizable|MultiAssetProxy|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestExchangeInternals|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|Whitelist).json" + "abis": "generated-artifacts/@(AssetProxyOwner|DutchAuction|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|MixinAuthorizable|MultiAssetProxy|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestExchangeInternals|TestStaticCallReceiver).json" }, "repository": { "type": "git", @@ -77,6 +77,7 @@ "@0x/contracts-multisig": "^1.0.0", "@0x/contracts-utils": "^1.0.0", "@0x/contracts-tokens": "^1.0.0", + "@0x/contracts-examples": "^1.0.0", "@0x/contracts-libs": "^1.0.0", "@0x/contracts-interfaces": "^1.0.0", "@0x/types": "^1.3.0", diff --git a/contracts/core/src/artifacts/index.ts b/contracts/core/src/artifacts/index.ts index ac334c173..7b598a6d9 100644 --- a/contracts/core/src/artifacts/index.ts +++ b/contracts/core/src/artifacts/index.ts @@ -5,7 +5,6 @@ import * as DutchAuction from '../../generated-artifacts/DutchAuction.json'; import * as ERC20Proxy from '../../generated-artifacts/ERC20Proxy.json'; import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json'; import * as Exchange from '../../generated-artifacts/Exchange.json'; -import * as ExchangeWrapper from '../../generated-artifacts/ExchangeWrapper.json'; import * as Forwarder from '../../generated-artifacts/Forwarder.json'; import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json'; import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json'; @@ -15,9 +14,6 @@ import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOw import * as TestExchangeInternals from '../../generated-artifacts/TestExchangeInternals.json'; import * as TestSignatureValidator from '../../generated-artifacts/TestSignatureValidator.json'; import * as TestStaticCallReceiver from '../../generated-artifacts/TestStaticCallReceiver.json'; -import * as Validator from '../../generated-artifacts/Validator.json'; -import * as Wallet from '../../generated-artifacts/Wallet.json'; -import * as Whitelist from '../../generated-artifacts/Whitelist.json'; export const artifacts = { AssetProxyOwner: AssetProxyOwner as ContractArtifact, @@ -25,7 +21,6 @@ export const artifacts = { ERC20Proxy: ERC20Proxy as ContractArtifact, ERC721Proxy: ERC721Proxy as ContractArtifact, Exchange: Exchange as ContractArtifact, - ExchangeWrapper: ExchangeWrapper as ContractArtifact, Forwarder: Forwarder as ContractArtifact, MixinAuthorizable: MixinAuthorizable as ContractArtifact, MultiAssetProxy: MultiAssetProxy as ContractArtifact, @@ -35,7 +30,4 @@ export const artifacts = { TestExchangeInternals: TestExchangeInternals as ContractArtifact, TestSignatureValidator: TestSignatureValidator as ContractArtifact, TestStaticCallReceiver: TestStaticCallReceiver as ContractArtifact, - Validator: Validator as ContractArtifact, - Wallet: Wallet as ContractArtifact, - Whitelist: Whitelist as ContractArtifact, }; diff --git a/contracts/core/src/wrappers/index.ts b/contracts/core/src/wrappers/index.ts index ff26a171e..ce3714ed7 100644 --- a/contracts/core/src/wrappers/index.ts +++ b/contracts/core/src/wrappers/index.ts @@ -3,7 +3,6 @@ export * from '../../generated-wrappers/dutch_auction'; export * from '../../generated-wrappers/erc20_proxy'; export * from '../../generated-wrappers/erc721_proxy'; export * from '../../generated-wrappers/exchange'; -export * from '../../generated-wrappers/exchange_wrapper'; export * from '../../generated-wrappers/forwarder'; export * from '../../generated-wrappers/mixin_authorizable'; export * from '../../generated-wrappers/order_validator'; @@ -12,6 +11,3 @@ export * from '../../generated-wrappers/test_asset_proxy_owner'; export * from '../../generated-wrappers/test_exchange_internals'; export * from '../../generated-wrappers/test_signature_validator'; export * from '../../generated-wrappers/test_static_call_receiver'; -export * from '../../generated-wrappers/validator'; -export * from '../../generated-wrappers/wallet'; -export * from '../../generated-wrappers/whitelist'; diff --git a/contracts/core/tsconfig.json b/contracts/core/tsconfig.json index ea493cbb8..d6adef2c5 100644 --- a/contracts/core/tsconfig.json +++ b/contracts/core/tsconfig.json @@ -12,7 +12,6 @@ "./generated-artifacts/ERC20Proxy.json", "./generated-artifacts/ERC721Proxy.json", "./generated-artifacts/Exchange.json", - "./generated-artifacts/ExchangeWrapper.json", "./generated-artifacts/Forwarder.json", "./generated-artifacts/MixinAuthorizable.json", "./generated-artifacts/MultiAssetProxy.json", @@ -21,10 +20,7 @@ "./generated-artifacts/TestAssetProxyOwner.json", "./generated-artifacts/TestExchangeInternals.json", "./generated-artifacts/TestSignatureValidator.json", - "./generated-artifacts/TestStaticCallReceiver.json", - "./generated-artifacts/Validator.json", - "./generated-artifacts/Wallet.json", - "./generated-artifacts/Whitelist.json" + "./generated-artifacts/TestStaticCallReceiver.json" ], "exclude": ["./deploy/solc/solc_bin"] } diff --git a/contracts/examples/.solhint.json b/contracts/examples/.solhint.json new file mode 100644 index 000000000..076afe9f3 --- /dev/null +++ b/contracts/examples/.solhint.json @@ -0,0 +1,20 @@ +{ + "extends": "default", + "rules": { + "avoid-low-level-calls": false, + "avoid-tx-origin": "warn", + "bracket-align": false, + "code-complexity": false, + "const-name-snakecase": "error", + "expression-indent": "error", + "function-max-lines": false, + "func-order": "error", + "indent": ["error", 4], + "max-line-length": ["warn", 160], + "no-inline-assembly": false, + "quotes": ["error", "double"], + "separate-by-one-line-in-contract": "error", + "space-after-comma": "error", + "statement-indent": "error" + } +} diff --git a/contracts/examples/README.md b/contracts/examples/README.md new file mode 100644 index 000000000..1c603bfcf --- /dev/null +++ b/contracts/examples/README.md @@ -0,0 +1,56 @@ +## Contract examples + +Smart contract examples of the 0x protocol. + +## Usage + +Contracts can be found in the [contracts](./contracts) directory. +This package contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others. + +## 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-examples yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0x/contracts-examples yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` diff --git a/contracts/examples/compiler.json b/contracts/examples/compiler.json new file mode 100644 index 000000000..375fa0c55 --- /dev/null +++ b/contracts/examples/compiler.json @@ -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": ["ExchangeWrapper", "Validator", "Wallet", "Whitelist"] +} diff --git a/contracts/examples/contracts/ExchangeWrapper/ExchangeWrapper.sol b/contracts/examples/contracts/ExchangeWrapper/ExchangeWrapper.sol new file mode 100644 index 000000000..d98136922 --- /dev/null +++ b/contracts/examples/contracts/ExchangeWrapper/ExchangeWrapper.sol @@ -0,0 +1,100 @@ +/* + + 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 "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; + + +contract ExchangeWrapper { + + // Exchange contract. + // solhint-disable-next-line var-name-mixedcase + IExchange internal EXCHANGE; + + constructor (address _exchange) + public + { + EXCHANGE = IExchange(_exchange); + } + + /// @dev Cancels all orders created by sender with a salt less than or equal to the targetOrderEpoch + /// and senderAddress equal to this contract. + /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled. + /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash. + /// @param makerSignature Proof that maker wishes to call this function with given params. + function cancelOrdersUpTo( + uint256 targetOrderEpoch, + uint256 salt, + bytes makerSignature + ) + external + { + address makerAddress = msg.sender; + + // Encode arguments into byte array. + bytes memory data = abi.encodeWithSelector( + EXCHANGE.cancelOrdersUpTo.selector, + targetOrderEpoch + ); + + // Call `cancelOrdersUpTo` via `executeTransaction`. + EXCHANGE.executeTransaction( + salt, + makerAddress, + data, + makerSignature + ); + } + + /// @dev Fills an order using `msg.sender` as the taker. + /// @param order Order struct containing order specifications. + /// @param takerAssetFillAmount Desired amount of takerAsset to sell. + /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash. + /// @param orderSignature Proof that order has been created by maker. + /// @param takerSignature Proof that taker wishes to call this function with given params. + function fillOrder( + LibOrder.Order memory order, + uint256 takerAssetFillAmount, + uint256 salt, + bytes memory orderSignature, + bytes memory takerSignature + ) + public + { + address takerAddress = msg.sender; + + // Encode arguments into byte array. + bytes memory data = abi.encodeWithSelector( + EXCHANGE.fillOrder.selector, + order, + takerAssetFillAmount, + orderSignature + ); + + // Call `fillOrder` via `executeTransaction`. + EXCHANGE.executeTransaction( + salt, + takerAddress, + data, + takerSignature + ); + } +} diff --git a/contracts/examples/contracts/Validator/Validator.sol b/contracts/examples/contracts/Validator/Validator.sol new file mode 100644 index 000000000..e488a9ca7 --- /dev/null +++ b/contracts/examples/contracts/Validator/Validator.sol @@ -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/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/IValidator.sol"; + + +contract Validator is + IValidator +{ + + // The single valid signer for this wallet. + // solhint-disable-next-line var-name-mixedcase + address internal VALID_SIGNER; + + /// @dev constructs a new `Validator` with a single valid signer. + /// @param validSigner The sole, valid signer. + constructor (address validSigner) public { + VALID_SIGNER = validSigner; + } + + /// @dev Verifies that a signature is valid. `signer` must match `VALID_SIGNER`. + /// @param hash Message hash that is signed. + /// @param signerAddress Address that should have signed the given hash. + /// @param signature Proof of signing. + /// @return Validity of signature. + // solhint-disable no-unused-vars + function isValidSignature( + bytes32 hash, + address signerAddress, + bytes signature + ) + external + view + returns (bool isValid) + { + return (signerAddress == VALID_SIGNER); + } + // solhint-enable no-unused-vars +} diff --git a/contracts/examples/contracts/Wallet/Wallet.sol b/contracts/examples/contracts/Wallet/Wallet.sol new file mode 100644 index 000000000..8edc74eb3 --- /dev/null +++ b/contracts/examples/contracts/Wallet/Wallet.sol @@ -0,0 +1,65 @@ +/* + + 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/IWallet.sol"; +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; + + +contract Wallet is + IWallet +{ + using LibBytes for bytes; + + // The owner of this wallet. + // solhint-disable-next-line var-name-mixedcase + address internal WALLET_OWNER; + + /// @dev constructs a new `Wallet` with a single owner. + /// @param walletOwner The owner of this wallet. + constructor (address walletOwner) public { + WALLET_OWNER = walletOwner; + } + + /// @dev Validates an EIP712 signature. + /// The signer must match the owner of this wallet. + /// @param hash Message hash that is signed. + /// @param eip712Signature Proof of signing. + /// @return Validity of signature. + function isValidSignature( + bytes32 hash, + bytes eip712Signature + ) + external + view + returns (bool isValid) + { + require( + eip712Signature.length == 65, + "LENGTH_65_REQUIRED" + ); + + uint8 v = uint8(eip712Signature[0]); + bytes32 r = eip712Signature.readBytes32(1); + bytes32 s = eip712Signature.readBytes32(33); + address recoveredAddress = ecrecover(hash, v, r, s); + isValid = WALLET_OWNER == recoveredAddress; + return isValid; + } +} diff --git a/contracts/examples/contracts/Whitelist/Whitelist.sol b/contracts/examples/contracts/Whitelist/Whitelist.sol new file mode 100644 index 000000000..2a3d33738 --- /dev/null +++ b/contracts/examples/contracts/Whitelist/Whitelist.sol @@ -0,0 +1,136 @@ +/* + + 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 "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; + + +contract Whitelist is + Ownable +{ + + // Mapping of address => whitelist status. + mapping (address => bool) public isWhitelisted; + + // Exchange contract. + // solhint-disable var-name-mixedcase + IExchange internal EXCHANGE; + bytes internal TX_ORIGIN_SIGNATURE; + // solhint-enable var-name-mixedcase + + byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x05"; + + constructor (address _exchange) + public + { + EXCHANGE = IExchange(_exchange); + TX_ORIGIN_SIGNATURE = abi.encodePacked(address(this), VALIDATOR_SIGNATURE_BYTE); + } + + /// @dev Adds or removes an address from the whitelist. + /// @param target Address to add or remove from whitelist. + /// @param isApproved Whitelist status to assign to address. + function updateWhitelistStatus( + address target, + bool isApproved + ) + external + onlyOwner + { + isWhitelisted[target] = isApproved; + } + + /// @dev Verifies signer is same as signer of current Ethereum transaction. + /// NOTE: This function can currently be used to validate signatures coming from outside of this contract. + /// Extra safety checks can be added for a production contract. + /// @param signerAddress Address that should have signed the given hash. + /// @param signature Proof of signing. + /// @return Validity of order signature. + // solhint-disable no-unused-vars + function isValidSignature( + bytes32 hash, + address signerAddress, + bytes signature + ) + external + view + returns (bool isValid) + { + // solhint-disable-next-line avoid-tx-origin + return signerAddress == tx.origin; + } + // solhint-enable no-unused-vars + + /// @dev Fills an order using `msg.sender` as the taker. + /// The transaction will revert if both the maker and taker are not whitelisted. + /// Orders should specify this contract as the `senderAddress` in order to gaurantee + /// that both maker and taker have been whitelisted. + /// @param order Order struct containing order specifications. + /// @param takerAssetFillAmount Desired amount of takerAsset to sell. + /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash. + /// @param orderSignature Proof that order has been created by maker. + function fillOrderIfWhitelisted( + LibOrder.Order memory order, + uint256 takerAssetFillAmount, + uint256 salt, + bytes memory orderSignature + ) + public + { + address takerAddress = msg.sender; + + // This contract must be the entry point for the transaction. + require( + // solhint-disable-next-line avoid-tx-origin + takerAddress == tx.origin, + "INVALID_SENDER" + ); + + // Check if maker is on the whitelist. + require( + isWhitelisted[order.makerAddress], + "MAKER_NOT_WHITELISTED" + ); + + // Check if taker is on the whitelist. + require( + isWhitelisted[takerAddress], + "TAKER_NOT_WHITELISTED" + ); + + // Encode arguments into byte array. + bytes memory data = abi.encodeWithSelector( + EXCHANGE.fillOrder.selector, + order, + takerAssetFillAmount, + orderSignature + ); + + // Call `fillOrder` via `executeTransaction`. + EXCHANGE.executeTransaction( + salt, + takerAddress, + data, + TX_ORIGIN_SIGNATURE + ); + } +} diff --git a/contracts/examples/package.json b/contracts/examples/package.json new file mode 100644 index 000000000..7682e0d45 --- /dev/null +++ b/contracts/examples/package.json @@ -0,0 +1,83 @@ +{ + "private": true, + "name": "@0x/contracts-examples", + "version": "1.0.0", + "engines": { + "node": ">=6.12" + }, + "description": "Smart contract examples 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", + "compile": "sol-compiler --contracts-dir contracts", + "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", + "lint-contracts": "solhint contracts/**/**/**/**/*.sol" + }, + "config": { + "abis": "generated-artifacts/@(ExchangeWrapper|Validator|Wallet|Whitelist).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/core/README.md", + "devDependencies": { + "@0x/contracts-test-utils": "^1.0.0", + "@0x/abi-gen": "^1.0.17", + "@0x/dev-utils": "^1.0.19", + "@0x/sol-compiler": "^1.1.14", + "@0x/sol-cov": "^2.1.14", + "@0x/subproviders": "^2.1.6", + "@0x/tslint-config": "^1.0.10", + "@types/bn.js": "^4.11.0", + "@types/lodash": "4.14.104", + "@types/node": "*", + "@types/yargs": "^10.0.0", + "chai": "^4.0.1", + "chai-as-promised": "^7.1.0", + "chai-bignumber": "^2.0.1", + "dirty-chai": "^2.0.1", + "make-promises-safe": "^1.1.0", + "ethereumjs-abi": "0.6.5", + "mocha": "^4.1.0", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "solc": "^0.4.24", + "solhint": "^1.2.1", + "tslint": "5.11.0", + "typescript": "3.0.1", + "yargs": "^10.0.3" + }, + "dependencies": { + "@0x/base-contract": "^3.0.8", + "@0x/order-utils": "^3.0.4", + "@0x/contracts-multisig": "^1.0.0", + "@0x/contracts-utils": "^1.0.0", + "@0x/contracts-tokens": "^1.0.0", + "@0x/contracts-libs": "^1.0.0", + "@0x/contracts-interfaces": "^1.0.0", + "@0x/types": "^1.3.0", + "@0x/typescript-typings": "^3.0.4", + "@0x/utils": "^2.0.6", + "@0x/web3-wrapper": "^3.1.6", + "@types/js-combinatorics": "^0.5.29", + "bn.js": "^4.11.8", + "ethereum-types": "^1.1.2", + "ethereumjs-util": "^5.1.1", + "lodash": "^4.17.5" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/contracts/examples/src/artifacts/index.ts b/contracts/examples/src/artifacts/index.ts new file mode 100644 index 000000000..c921fbf89 --- /dev/null +++ b/contracts/examples/src/artifacts/index.ts @@ -0,0 +1,13 @@ +import { ContractArtifact } from 'ethereum-types'; + +import * as ExchangeWrapper from '../../generated-artifacts/ExchangeWrapper.json'; +import * as Validator from '../../generated-artifacts/Validator.json'; +import * as Wallet from '../../generated-artifacts/Wallet.json'; +import * as Whitelist from '../../generated-artifacts/Whitelist.json'; + +export const artifacts = { + ExchangeWrapper: ExchangeWrapper as ContractArtifact, + Validator: Validator as ContractArtifact, + Wallet: Wallet as ContractArtifact, + Whitelist: Whitelist as ContractArtifact, +}; diff --git a/contracts/examples/src/index.ts b/contracts/examples/src/index.ts new file mode 100644 index 000000000..d55f08ea2 --- /dev/null +++ b/contracts/examples/src/index.ts @@ -0,0 +1,2 @@ +export * from './artifacts'; +export * from './wrappers'; diff --git a/contracts/examples/src/wrappers/index.ts b/contracts/examples/src/wrappers/index.ts new file mode 100644 index 000000000..dc67277d7 --- /dev/null +++ b/contracts/examples/src/wrappers/index.ts @@ -0,0 +1,4 @@ +export * from '../../generated-wrappers/exchange_wrapper'; +export * from '../../generated-wrappers/validator'; +export * from '../../generated-wrappers/wallet'; +export * from '../../generated-wrappers/whitelist'; diff --git a/contracts/examples/tsconfig.json b/contracts/examples/tsconfig.json new file mode 100644 index 000000000..63245da1e --- /dev/null +++ b/contracts/examples/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": ".", + "resolveJsonModule": true + }, + "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], + "files": [ + "./generated-artifacts/ExchangeWrapper.json", + "./generated-artifacts/Validator.json", + "./generated-artifacts/Wallet.json", + "./generated-artifacts/Whitelist.json" + ], + "exclude": ["./deploy/solc/solc_bin"] +} diff --git a/contracts/examples/tslint.json b/contracts/examples/tslint.json new file mode 100644 index 000000000..1bb3ac2a2 --- /dev/null +++ b/contracts/examples/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["@0x/tslint-config"], + "rules": { + "custom-no-magic-numbers": false + } +} -- cgit