Compare commits
68 Commits
ethereum-t
...
@0xproject
Author | SHA1 | Date | |
---|---|---|---|
|
599554b785 | ||
|
d57d282cab | ||
|
562bef98e2 | ||
|
900f819be8 | ||
|
e7337c2451 | ||
|
dc81193132 | ||
|
fa868b4963 | ||
|
62945ad363 | ||
|
61c38d35be | ||
|
4e0ec72896 | ||
|
c28289e9a8 | ||
|
e7e9ddf232 | ||
|
f03784ba37 | ||
|
2445e23c0b | ||
|
cd29483187 | ||
|
9bacbdab48 | ||
|
551d484fb7 | ||
|
ff66432b83 | ||
|
a7ae82a2d1 | ||
|
5f34b5a80e | ||
|
8fca2a8116 | ||
|
5472500119 | ||
|
8fb5c29b4b | ||
|
40a061a5ca | ||
|
2ef82592a3 | ||
|
14b5448d70 | ||
|
e7d45e47bf | ||
|
28268d4355 | ||
|
50fa02c1d1 | ||
|
b36ff9103d | ||
|
f032c2466c | ||
|
b63ddc9be4 | ||
|
171430b617 | ||
|
d561043774 | ||
|
b1871e9ddd | ||
|
b4a5e7258c | ||
|
3c75debdf9 | ||
|
84d1053f73 | ||
|
f9df42f5d9 | ||
|
4414ef0a0f | ||
|
b7729ada38 | ||
|
3da67feeb2 | ||
|
8a0d563a32 | ||
|
612fc4a949 | ||
|
bf915ce403 | ||
|
0f9ea9773e | ||
|
447a3a6c26 | ||
|
f1cc16c44d | ||
|
aae16b6343 | ||
|
834e1538d1 | ||
|
afc489bc2c | ||
|
3e061e7364 | ||
|
6395c2a8b2 | ||
|
c8225288cd | ||
|
4a108aa67d | ||
|
fd9b3e0dcf | ||
|
f94b647e61 | ||
|
2eccc3efaf | ||
|
972341725e | ||
|
40b10fd29d | ||
|
b31fcffc76 | ||
|
ec222ea0cd | ||
|
5533220da0 | ||
|
6ee7024457 | ||
|
f839ac9c58 | ||
|
1a8b1460a6 | ||
|
feac0779a4 | ||
|
d9eeb0421c |
@@ -11,27 +11,23 @@ jobs:
|
||||
- checkout
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
- restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-{{ .Branch }}
|
||||
- yarn-packages-master
|
||||
- yarn-packages-
|
||||
key: dependency-cache-v1-{{ checksum "package.json" }}
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile install
|
||||
command: yarn --frozen-lockfile
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
key: dependency-cache-v1-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- node_modules/
|
||||
- ./node_modules
|
||||
- run: wget https://s3.amazonaws.com/testrpc-shapshots/${CONTRACTS_COMMIT_HASH}.zip
|
||||
- run: unzip ${CONTRACTS_COMMIT_HASH}.zip -d testrpc_snapshot
|
||||
- run: node ./node_modules/lerna/bin/lerna.js bootstrap
|
||||
- run: yarn build
|
||||
- save_cache:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo
|
||||
test-1:
|
||||
test-installation:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
@@ -39,16 +35,24 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0xproject/contract-wrappers
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-compiler
|
||||
- run: yarn test:installation
|
||||
test-0xjs:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci 0x.js
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
key: coverage-0xjs-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contract-wrappers/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-compiler/coverage/lcov.info
|
||||
- ~/repo/packages/0x.js/coverage/lcov.info
|
||||
test-contracts:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
@@ -57,8 +61,16 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci contracts
|
||||
test-2:
|
||||
- save_cache:
|
||||
key: coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contracts/coverage/lcov.info
|
||||
test-sol-compiler:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
@@ -66,13 +78,28 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0xproject/assert
|
||||
- run: yarn wsrun test:circleci @0xproject/connect
|
||||
- run: yarn wsrun test:circleci @0xproject/dev-utils
|
||||
- run: yarn wsrun test:circleci @0xproject/json-schemas
|
||||
- run: yarn wsrun test:circleci @0xproject/subproviders
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-cov
|
||||
- run: yarn wsrun test:circleci @0xproject/metacoin
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-compiler
|
||||
- save_cache:
|
||||
key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-compiler/coverage/lcov.info
|
||||
test-rest:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci --exclude contracts --exclude 0x.js --exclude @0xproject/sol-compiler --stages --exclude-missing
|
||||
- save_cache:
|
||||
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
@@ -101,7 +128,16 @@ jobs:
|
||||
key: coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/metacoin/coverage/lcov.info
|
||||
static-tests:
|
||||
lint:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn lerna:run lint
|
||||
prettier:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
@@ -110,7 +146,6 @@ jobs:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn prettier:ci
|
||||
- run: yarn lerna:run lint
|
||||
submit-coverage:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
@@ -119,15 +154,15 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
@@ -140,9 +175,6 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-cov-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
@@ -158,19 +190,30 @@ workflows:
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- test-1:
|
||||
- test-installation:
|
||||
requires:
|
||||
- build
|
||||
- test-2:
|
||||
- test-0xjs:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts:
|
||||
requires:
|
||||
- build
|
||||
- static-tests:
|
||||
- test-sol-compiler:
|
||||
requires:
|
||||
- build
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
- prettier:
|
||||
requires:
|
||||
- build
|
||||
- lint:
|
||||
requires:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-1
|
||||
- test-2
|
||||
- test-0xjs
|
||||
- test-sol-compiler
|
||||
- test-rest
|
||||
- test-contracts
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -86,11 +86,12 @@ packages/contract-wrappers/src/contract_wrappers/generated/
|
||||
packages/metacoin/src/contract_wrappers
|
||||
packages/fill-scenarios/src/generated_contract_wrappers/
|
||||
packages/order-watcher/src/generated_contract_wrappers/
|
||||
packages/migrations/src/v1/contract_wrappers
|
||||
packages/migrations/src/v2/contract_wrappers
|
||||
packages/migrations/src/contract_wrappers
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
||||
# Monorepo scripts
|
||||
packages/*/scripts/
|
||||
|
||||
ganache.log
|
||||
|
@@ -6,6 +6,5 @@ lib
|
||||
/packages/contract-wrappers/test/artifacts
|
||||
/packages/order-watcher/test/artifacts
|
||||
/packages/migrations/artifacts/1.0.0
|
||||
/packages/migrations/artifacts/2.0.0
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
|
21
package.json
21
package.json
@@ -13,8 +13,9 @@
|
||||
"prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc",
|
||||
"report_coverage": "lcov-result-merger 'packages/*/coverage/lcov.info' | coveralls",
|
||||
"test:installation": "node ./packages/monorepo-scripts/lib/test_installation.js",
|
||||
"run:publish": "run-s install:all rebuild script:publish",
|
||||
"run:publish:dry": "run-s install:all rebuild script:publish:dry",
|
||||
"run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish",
|
||||
"run:publish:dry": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish:dry",
|
||||
"script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js",
|
||||
"script:publish": "node ./packages/monorepo-scripts/lib/publish.js",
|
||||
"script:publish:dry": "IS_DRY_RUN=true yarn script:publish",
|
||||
"install:all": "yarn install",
|
||||
@@ -22,26 +23,24 @@
|
||||
"lerna:run": "lerna run",
|
||||
"watch": "wsrun watch $PKG --fast-exit -r --stages --done-criteria='complete|successfully'",
|
||||
"build": "wsrun build $PKG --fast-exit -r --stages",
|
||||
"build:monorepo_scripts": "PKG=@0xproject/monorepo-scripts yarn build",
|
||||
"clean": "wsrun clean $PKG --fast-exit -r --parallel",
|
||||
"rebuild": "run-s clean build",
|
||||
"test": "wsrun test $PKG --fast-exit --serial --exclude-missing",
|
||||
"stage_docs": "wsrun docs:stage $PKG --fast-exit --parallel --exclude-missing",
|
||||
"lint": "wsrun lint $PKG --fast-exit --parallel --exclude-missing"
|
||||
"test": "wsrun test $PKG --serial --exclude-missing",
|
||||
"stage_docs": "wsrun docs:stage $PKG --parallel --exclude-missing",
|
||||
"lint": "wsrun lint $PKG --parallel --exclude-missing"
|
||||
},
|
||||
"config": {
|
||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async-child-process": "^1.1.1",
|
||||
"async-child-process": "1.1.1",
|
||||
"coveralls": "^3.0.0",
|
||||
"ganache-cli": "^6.1.0",
|
||||
"lcov-result-merger": "^3.0.0",
|
||||
"lerna": "^2.5.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"npm-run-all": "4.1.2",
|
||||
"prettier": "1.12.1",
|
||||
"wsrun": "^2.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"ethereumjs-tx": "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
|
||||
}
|
||||
}
|
||||
|
@@ -9,3 +9,5 @@ test/
|
||||
/generated_docs/
|
||||
/scripts/
|
||||
/lib/src/monorepo_scripts/
|
||||
/lib/test/
|
||||
ganache.log
|
||||
|
@@ -1,6 +1,42 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1527809861,
|
||||
"timestamp": 1531149657,
|
||||
"version": "0.38.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.38.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527617805,
|
||||
"version": "0.38.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527617227,
|
||||
"version": "0.38.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527616612,
|
||||
"version": "0.38.1",
|
||||
"changes": [
|
||||
{
|
||||
|
@@ -5,7 +5,23 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.38.1 - _May 31, 2018_
|
||||
## v0.38.5 - _July 9, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.38.4 - _June 19, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.38.3 - _May 29, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.38.2 - _May 29, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.38.1 - _May 29, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@@ -14,7 +30,7 @@ CHANGELOG
|
||||
* Renamed createOrderStateWatcher to createOrderWatcherAsync since it is now async (#579)
|
||||
* Renamed ZeroExError to ContractWrappersErrors since they now lives in the @0xproject/contract-wrappers subpackage (#579)
|
||||
|
||||
## v0.37.2 - _May 4, 2018_
|
||||
## v0.37.2 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "0.38.0",
|
||||
"version": "0.38.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,7 +44,6 @@
|
||||
"docPublishConfigs": {
|
||||
"extraFileIncludes": [
|
||||
"../types/src/index.ts",
|
||||
"../ethereum-types/src/index.ts",
|
||||
"../contract-wrappers/src/types.ts",
|
||||
"../contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts",
|
||||
"../contract-wrappers/src/contract_wrappers/exchange_wrapper.ts",
|
||||
@@ -67,51 +66,49 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^0.3.0",
|
||||
"@0xproject/dev-utils": "^0.4.2",
|
||||
"@0xproject/migrations": "^0.0.6",
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@0xproject/abi-gen": "^0.3.3",
|
||||
"@0xproject/dev-utils": "^0.4.5",
|
||||
"@0xproject/migrations": "^0.0.9",
|
||||
"@0xproject/monorepo-scripts": "^0.2.2",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/sinon": "^2.2.2",
|
||||
"awesome-typescript-loader": "^3.1.3",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^2.0.1",
|
||||
"copyfiles": "^1.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"json-loader": "^0.5.4",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"opn-cli": "^3.1.0",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"sinon": "^4.0.0",
|
||||
"source-map-support": "^0.5.0",
|
||||
"@types/mocha": "2.2.48",
|
||||
"@types/node": "9.6.0",
|
||||
"@types/sinon": "2.3.7",
|
||||
"awesome-typescript-loader": "3.5.0",
|
||||
"chai": "4.1.2",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chai-bignumber": "2.0.1",
|
||||
"copyfiles": "1.2.0",
|
||||
"dirty-chai": "2.0.1",
|
||||
"json-loader": "0.5.7",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"mocha": "4.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"nyc": "11.6.0",
|
||||
"opn-cli": "3.1.0",
|
||||
"prettier": "1.12.1",
|
||||
"shx": "0.2.2",
|
||||
"sinon": "4.4.9",
|
||||
"source-map-support": "0.5.4",
|
||||
"tslint": "5.8.0",
|
||||
"typedoc": "0xProject/typedoc",
|
||||
"typescript": "2.7.1",
|
||||
"webpack": "^3.1.0"
|
||||
"webpack": "3.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.2.10",
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/contract-wrappers": "^0.0.2",
|
||||
"@0xproject/order-utils": "^0.0.5",
|
||||
"@0xproject/order-watcher": "^0.0.2",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/types": "0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"ethers": "^3.0.15",
|
||||
"lodash": "^4.17.4"
|
||||
"@0xproject/assert": "^0.2.13",
|
||||
"@0xproject/base-contract": "^0.3.5",
|
||||
"@0xproject/contract-wrappers": "^0.1.0",
|
||||
"@0xproject/order-utils": "^0.0.8",
|
||||
"@0xproject/order-watcher": "^0.0.7",
|
||||
"@0xproject/sol-compiler": "^0.5.3",
|
||||
"@0xproject/types": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"@0xproject/web3-wrapper": "^0.7.2",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "4.17.10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -19,6 +19,8 @@ export {
|
||||
TransactionReceiptWithDecodedLogs,
|
||||
} from '@0xproject/types';
|
||||
|
||||
export { OrderWatcherConfig } from '@0xproject/order-watcher';
|
||||
|
||||
export {
|
||||
EventCallback,
|
||||
ContractEvent,
|
||||
|
@@ -15,7 +15,7 @@ const TIMEOUT = 10000;
|
||||
describe('Artifacts', () => {
|
||||
describe('contracts are deployed on kovan', () => {
|
||||
const kovanRpcUrl = constants.KOVAN_RPC_URL;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
|
||||
const provider = web3Factory.create({ rpcUrl: kovanRpcUrl }).currentProvider;
|
||||
const config = {
|
||||
networkId: constants.KOVAN_NETWORK_ID,
|
||||
};
|
||||
@@ -32,7 +32,7 @@ describe('Artifacts', () => {
|
||||
});
|
||||
describe('contracts are deployed on ropsten', () => {
|
||||
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
|
||||
const provider = web3Factory.create({ rpcUrl: ropstenRpcUrl }).currentProvider;
|
||||
const config = {
|
||||
networkId: constants.ROPSTEN_NETWORK_ID,
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { runV1MigrationsAsync } from '@0xproject/migrations';
|
||||
import { runMigrationsAsync } from '@0xproject/migrations';
|
||||
import * as path from 'path';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
@@ -11,9 +11,9 @@ before('migrate contracts', async function(): Promise<void> {
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
gas: devConstants.GAS_ESTIMATE,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
const artifactsDir = `../migrations/artifacts/1.0.0`;
|
||||
await runV1MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
await runMigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
});
|
||||
|
@@ -2,7 +2,8 @@ import { devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { Provider } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
|
||||
const provider: Provider = web3.currentProvider;
|
||||
const web3Wrapper = new Web3Wrapper(web3.currentProvider);
|
||||
|
||||
export { provider, web3Wrapper };
|
||||
|
@@ -1,13 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1527809861,
|
||||
"version": "0.3.1",
|
||||
"timestamp": 1531149657,
|
||||
"version": "0.3.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.3.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.3.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Incorrect publish that was unpublished"
|
||||
}
|
||||
],
|
||||
"timestamp": 1527810075
|
||||
},
|
||||
{
|
||||
"version": "0.3.0",
|
||||
"changes": [
|
||||
|
@@ -5,15 +5,23 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.3.1 - _May 31, 2018_
|
||||
## v0.3.3 - _July 9, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.3.2 - _June 19, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.3.1 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
## v0.3.0 - _May 22, 2018_
|
||||
|
||||
* Properly export the executable binary (#588)
|
||||
|
||||
## v0.2.13 - _May 4, 2018_
|
||||
## v0.2.13 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/abi-gen",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.3",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -27,29 +27,29 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"chalk": "^2.3.0",
|
||||
"glob": "^7.1.2",
|
||||
"handlebars": "^4.0.11",
|
||||
"lodash": "^4.17.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"to-snake-case": "^1.0.0",
|
||||
"yargs": "^10.0.3"
|
||||
"@0xproject/types": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"chalk": "2.3.2",
|
||||
"glob": "7.1.1",
|
||||
"handlebars": "4.0.11",
|
||||
"lodash": "4.17.10",
|
||||
"mkdirp": "0.5.1",
|
||||
"to-snake-case": "1.0.0",
|
||||
"yargs": "11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@types/glob": "^5.0.33",
|
||||
"@types/handlebars": "^4.0.36",
|
||||
"@types/mkdirp": "^0.5.1",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/yargs": "^10.0.0",
|
||||
"copyfiles": "^1.2.0",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"@0xproject/monorepo-scripts": "^0.2.2",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/glob": "5.0.35",
|
||||
"@types/handlebars": "4.0.36",
|
||||
"@types/mkdirp": "0.5.2",
|
||||
"@types/node": "9.6.0",
|
||||
"@types/yargs": "10.0.2",
|
||||
"copyfiles": "1.2.0",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"shx": "0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { AbiDefinition, ConstructorAbi, EventAbi, MethodAbi } from '@0xproject/types';
|
||||
import { abiUtils, logUtils } from '@0xproject/utils';
|
||||
import chalk from 'chalk';
|
||||
import { AbiDefinition, ConstructorAbi, EventAbi, MethodAbi } from 'ethereum-types';
|
||||
import * as fs from 'fs';
|
||||
import { sync as globSync } from 'glob';
|
||||
import * as Handlebars from 'handlebars';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { EventAbi, MethodAbi } from 'ethereum-types';
|
||||
import { EventAbi, MethodAbi } from '@0xproject/types';
|
||||
|
||||
export enum ParamKind {
|
||||
Input = 'input',
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { AbiType, ConstructorAbi, DataItem } from 'ethereum-types';
|
||||
import { AbiType, ConstructorAbi, DataItem } from '@0xproject/types';
|
||||
import * as fs from 'fs';
|
||||
import * as _ from 'lodash';
|
||||
import * as path from 'path';
|
||||
|
@@ -1,13 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1527809861,
|
||||
"version": "0.2.11",
|
||||
"timestamp": 1531149657,
|
||||
"version": "0.2.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.2.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.2.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Incorrect publish that was unpublished"
|
||||
}
|
||||
],
|
||||
"timestamp": 1527810075
|
||||
},
|
||||
{
|
||||
"timestamp": 1527008270,
|
||||
"version": "0.2.10",
|
||||
|
@@ -5,15 +5,23 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.2.11 - _May 31, 2018_
|
||||
## v0.2.13 - _July 9, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.2.12 - _June 19, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.2.11 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
## v0.2.10 - _May 22, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.2.9 - _May 4, 2018_
|
||||
## v0.2.9 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/assert",
|
||||
"version": "0.2.10",
|
||||
"version": "0.2.13",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -30,28 +30,28 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@0xproject/monorepo-scripts": "^0.2.2",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/valid-url": "^1.0.2",
|
||||
"chai": "^4.0.1",
|
||||
"copyfiles": "^1.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"shx": "^0.2.2",
|
||||
"@types/mocha": "2.2.48",
|
||||
"@types/valid-url": "1.0.2",
|
||||
"chai": "4.1.2",
|
||||
"copyfiles": "1.2.0",
|
||||
"dirty-chai": "2.0.1",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"mocha": "4.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"nyc": "11.6.0",
|
||||
"shx": "0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/json-schemas": "0.7.22",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"lodash": "^4.17.4",
|
||||
"valid-url": "^1.0.9"
|
||||
"@0xproject/json-schemas": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"lodash": "4.17.10",
|
||||
"valid-url": "1.0.9"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -64,9 +64,6 @@ export const assert = {
|
||||
this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Provider', value));
|
||||
},
|
||||
doesConformToSchema(variableName: string, value: any, schema: Schema, subSchemas?: Schema[]): void {
|
||||
if (_.isUndefined(value)) {
|
||||
throw new Error(`${variableName} can't be undefined`);
|
||||
}
|
||||
const schemaValidator = new SchemaValidator();
|
||||
if (!_.isUndefined(subSchemas)) {
|
||||
_.map(subSchemas, schemaValidator.addSchema.bind(schemaValidator));
|
||||
|
@@ -1,13 +1,32 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1527809861,
|
||||
"version": "0.3.3",
|
||||
"timestamp": 1531149657,
|
||||
"version": "0.3.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.3.4",
|
||||
"changes": [
|
||||
{
|
||||
"note":
|
||||
"Update EthersJs to fix the `value.toLowerCase()` is not a function bug caused by `ethers.js` breaking patch version https://github.com/ethers-io/ethers.js/issues/201"
|
||||
}
|
||||
],
|
||||
"timestamp": 1529397769
|
||||
},
|
||||
{
|
||||
"timestamp": 1527810075,
|
||||
"version": "0.3.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Incorrect publish that was unpublished"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527008270,
|
||||
"version": "0.3.2",
|
||||
|
@@ -5,15 +5,23 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.3.3 - _May 31, 2018_
|
||||
## v0.3.5 - _July 9, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.3.4 - _June 19, 2018_
|
||||
|
||||
* Update EthersJs to fix the `value.toLowerCase()` is not a function bug caused by `ethers.js` breaking patch version https://github.com/ethers-io/ethers.js/issues/201
|
||||
|
||||
## v0.3.3 - _June 1, 2018_
|
||||
|
||||
* Incorrect publish that was unpublished
|
||||
|
||||
## v0.3.2 - _May 22, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.3.1 - _May 4, 2018_
|
||||
## v0.3.1 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/base-contract",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -29,25 +29,25 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@0xproject/monorepo-scripts": "^0.2.2",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/lodash": "4.14.104",
|
||||
"chai": "^4.0.1",
|
||||
"copyfiles": "^1.2.0",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"chai": "4.1.2",
|
||||
"copyfiles": "1.2.0",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"mocha": "4.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"shx": "0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ethereum-types": "^0.0.1",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethers": "^3.0.15",
|
||||
"lodash": "^4.17.4"
|
||||
"@0xproject/types": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"@0xproject/web3-wrapper": "^0.7.2",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "4.17.10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import { abiUtils, BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import {
|
||||
AbiDefinition,
|
||||
AbiType,
|
||||
@@ -10,7 +8,9 @@ import {
|
||||
Provider,
|
||||
TxData,
|
||||
TxDataPayable,
|
||||
} from 'ethereum-types';
|
||||
} from '@0xproject/types';
|
||||
import { abiUtils, BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { DataItem } from 'ethereum-types';
|
||||
import { DataItem } from '@0xproject/types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
// tslint:disable-next-line:completed-docs
|
||||
|
@@ -1,6 +1,24 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1527809861,
|
||||
"timestamp": 1531149657,
|
||||
"version": "0.6.16",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.6.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527616612,
|
||||
"version": "0.6.14",
|
||||
"changes": [
|
||||
{
|
||||
|
@@ -5,7 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.6.14 - _May 31, 2018_
|
||||
## v0.6.16 - _July 9, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.6.15 - _June 19, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.6.14 - _May 29, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
@@ -13,7 +21,7 @@ CHANGELOG
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.6.12 - _May 4, 2018_
|
||||
## v0.6.12 - _May 5, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/connect",
|
||||
"version": "0.6.13",
|
||||
"version": "0.6.16",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,37 +50,37 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.2.10",
|
||||
"@0xproject/json-schemas": "0.7.22",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"lodash": "^4.17.4",
|
||||
"query-string": "^5.0.1",
|
||||
"websocket": "^1.0.25"
|
||||
"@0xproject/assert": "^0.2.13",
|
||||
"@0xproject/json-schemas": "^0.8.2",
|
||||
"@0xproject/types": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"lodash": "4.17.10",
|
||||
"query-string": "4.3.4",
|
||||
"websocket": "1.0.25"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@types/fetch-mock": "^5.12.1",
|
||||
"@0xproject/monorepo-scripts": "^0.2.2",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/fetch-mock": "5.12.2",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/query-string": "^5.0.1",
|
||||
"@types/websocket": "^0.0.34",
|
||||
"async-child-process": "^1.1.1",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"copyfiles": "^1.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"fetch-mock": "^5.13.1",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"shx": "^0.2.2",
|
||||
"@types/mocha": "2.2.48",
|
||||
"@types/query-string": "5.1.0",
|
||||
"@types/websocket": "0.0.34",
|
||||
"async-child-process": "1.1.1",
|
||||
"chai": "4.1.2",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"copyfiles": "1.2.0",
|
||||
"dirty-chai": "2.0.1",
|
||||
"fetch-mock": "5.13.1",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"mocha": "4.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"nyc": "11.6.0",
|
||||
"shx": "0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
"typedoc": "~0.8.0",
|
||||
"typedoc": "0.8.0",
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -17,4 +17,4 @@ export {
|
||||
WebSocketOrderbookChannelConfig,
|
||||
} from './types';
|
||||
|
||||
export { Order, SignedOrder } from '@0xproject/types';
|
||||
export { ECSignature, Order, SignedOrder } from '@0xproject/types';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Order, SignedOrder } from '@0xproject/types';
|
||||
import { ECSignature, Order, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export interface Client {
|
||||
@@ -16,7 +16,7 @@ export interface OrderbookChannel {
|
||||
}
|
||||
|
||||
/**
|
||||
* heartbeatInterval: Interval in milliseconds that the orderbook channel should ping the underlying websocket. Default: 15000
|
||||
* heartbeatIntervalMs: Interval in milliseconds that the orderbook channel should ping the underlying websocket. Default: 15000
|
||||
*/
|
||||
export interface WebSocketOrderbookChannelConfig {
|
||||
heartbeatIntervalMs?: number;
|
||||
|
@@ -1,6 +1,34 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1527809861,
|
||||
"version": "0.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note":
|
||||
"Update Blockstream dep. to V5.0 and no longer force unsubscribe on blockstream error (which are not recoverable)"
|
||||
}
|
||||
],
|
||||
"timestamp": 1531149657
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527617227,
|
||||
"version": "0.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527616612,
|
||||
"version": "0.0.3",
|
||||
"changes": [
|
||||
{
|
||||
|
@@ -5,7 +5,19 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.0.3 - _May 31, 2018_
|
||||
## v0.1.0 - _July 9, 2018_
|
||||
|
||||
* Update Blockstream dep. to V5.0 and no longer force unsubscribe on blockstream error (which are not recoverable)
|
||||
|
||||
## v0.0.5 - _June 19, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.4 - _May 29, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.3 - _May 29, 2018_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/contract-wrappers",
|
||||
"version": "0.0.2",
|
||||
"version": "0.1.0",
|
||||
"description": "Smart TS wrappers for 0x smart contracts",
|
||||
"keywords": [
|
||||
"0xproject",
|
||||
@@ -27,13 +27,7 @@
|
||||
},
|
||||
"config": {
|
||||
"compact_artifacts": "Exchange DummyToken ZRXToken Token EtherToken TokenTransferProxy TokenRegistry",
|
||||
"contracts": "Exchange DummyToken ZRXToken Token WETH9 TokenTransferProxy_v1 MultiSigWallet MultiSigWalletWithTimeLock MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress MaliciousToken TokenRegistry Arbitrage EtherDelta AccountLevels",
|
||||
"postpublish": {
|
||||
"assets": [
|
||||
"packages/contract-wrappers/_bundles/index.js",
|
||||
"packages/contract-wrappers/_bundles/index.min.js"
|
||||
]
|
||||
}
|
||||
"contracts": "Exchange DummyToken ZRXToken Token WETH9 TokenTransferProxy MultiSigWallet MultiSigWalletWithTimeLock MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress MaliciousToken TokenRegistry Arbitrage EtherDelta AccountLevels"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -44,54 +38,53 @@
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^0.3.0",
|
||||
"@0xproject/dev-utils": "^0.4.2",
|
||||
"@0xproject/migrations": "^0.0.6",
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/subproviders": "^0.10.2",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@0xproject/abi-gen": "^0.3.3",
|
||||
"@0xproject/dev-utils": "^0.4.5",
|
||||
"@0xproject/migrations": "^0.0.9",
|
||||
"@0xproject/monorepo-scripts": "^0.2.2",
|
||||
"@0xproject/sol-compiler": "^0.5.3",
|
||||
"@0xproject/subproviders": "^0.10.5",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/sinon": "^2.2.2",
|
||||
"@types/uuid": "^3.4.2",
|
||||
"awesome-typescript-loader": "^3.1.3",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^2.0.1",
|
||||
"copyfiles": "^1.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"opn-cli": "^3.1.0",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"sinon": "^4.0.0",
|
||||
"source-map-support": "^0.5.0",
|
||||
"@types/mocha": "2.2.48",
|
||||
"@types/node": "9.6.0",
|
||||
"@types/sinon": "2.3.7",
|
||||
"@types/uuid": "3.4.3",
|
||||
"awesome-typescript-loader": "3.5.0",
|
||||
"chai": "4.1.2",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chai-bignumber": "2.0.1",
|
||||
"copyfiles": "1.2.0",
|
||||
"dirty-chai": "2.0.1",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"mocha": "4.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"nyc": "11.6.0",
|
||||
"opn-cli": "3.1.0",
|
||||
"prettier": "1.12.1",
|
||||
"shx": "0.2.2",
|
||||
"sinon": "4.4.9",
|
||||
"source-map-support": "0.5.4",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.7.1",
|
||||
"web3-provider-engine": "^14.0.4"
|
||||
"web3-provider-engine": "13.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.2.10",
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/fill-scenarios": "^0.0.2",
|
||||
"@0xproject/json-schemas": "0.7.22",
|
||||
"@0xproject/order-utils": "^0.0.5",
|
||||
"@0xproject/types": "0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"ethereumjs-blockstream": "^2.0.6",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "^3.0.15",
|
||||
"js-sha3": "^0.7.0",
|
||||
"lodash": "^4.17.4",
|
||||
"uuid": "^3.1.0"
|
||||
"@0xproject/assert": "^0.2.13",
|
||||
"@0xproject/base-contract": "^0.3.5",
|
||||
"@0xproject/fill-scenarios": "^0.0.5",
|
||||
"@0xproject/json-schemas": "^0.8.2",
|
||||
"@0xproject/order-utils": "^0.0.8",
|
||||
"@0xproject/types": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"@0xproject/web3-wrapper": "^0.7.2",
|
||||
"ethereumjs-blockstream": "5.0.0",
|
||||
"ethereumjs-util": "5.1.5",
|
||||
"ethers": "3.0.22",
|
||||
"js-sha3": "0.7.0",
|
||||
"lodash": "4.17.10",
|
||||
"uuid": "3.2.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -9,7 +9,7 @@ import {
|
||||
} from '@0xproject/types';
|
||||
import { AbiDecoder, intervalUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
|
||||
import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
@@ -38,7 +38,7 @@ const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
|
||||
export class ContractWrapper {
|
||||
protected _web3Wrapper: Web3Wrapper;
|
||||
protected _networkId: number;
|
||||
private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
|
||||
private _blockAndLogStreamerIfExists?: BlockAndLogStreamer<Block, Log> | undefined;
|
||||
private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
|
||||
private _filters: { [filterToken: string]: FilterObject };
|
||||
private _filterCallbacks: {
|
||||
@@ -46,6 +46,10 @@ export class ContractWrapper {
|
||||
};
|
||||
private _onLogAddedSubscriptionToken: string | undefined;
|
||||
private _onLogRemovedSubscriptionToken: string | undefined;
|
||||
private static _onBlockstreamError(err: Error): void {
|
||||
// Noop on blockstream errors since they are automatically
|
||||
// recovered from and don't cause Blockstream to exit.
|
||||
}
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number) {
|
||||
this._web3Wrapper = web3Wrapper;
|
||||
this._networkId = networkId;
|
||||
@@ -162,13 +166,14 @@ export class ContractWrapper {
|
||||
this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
|
||||
this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
|
||||
this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
|
||||
ContractWrapper._onBlockstreamError.bind(this),
|
||||
);
|
||||
const catchAllLogFilter = {};
|
||||
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
|
||||
this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this._reconcileBlockAsync.bind(this),
|
||||
constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
||||
this._onReconcileBlockError.bind(this),
|
||||
ContractWrapper._onBlockstreamError.bind(this),
|
||||
);
|
||||
let isRemoved = false;
|
||||
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
|
||||
@@ -179,12 +184,6 @@ export class ContractWrapper {
|
||||
this._onLogStateChanged.bind(this, isRemoved),
|
||||
);
|
||||
}
|
||||
private _onReconcileBlockError(err: Error): void {
|
||||
const filterTokens = _.keys(this._filterCallbacks);
|
||||
_.each(filterTokens, filterToken => {
|
||||
this._unsubscribe(filterToken, err);
|
||||
});
|
||||
}
|
||||
private _setNetworkId(networkId: number): void {
|
||||
this._networkId = networkId;
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ const TIMEOUT = 10000;
|
||||
describe('Artifacts', () => {
|
||||
describe('contracts are deployed on kovan', () => {
|
||||
const kovanRpcUrl = constants.KOVAN_RPC_URL;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
|
||||
const provider = web3Factory.create({ rpcUrl: kovanRpcUrl }).currentProvider;
|
||||
const config = {
|
||||
networkId: constants.KOVAN_NETWORK_ID,
|
||||
};
|
||||
@@ -32,7 +32,7 @@ describe('Artifacts', () => {
|
||||
});
|
||||
describe('contracts are deployed on ropsten', () => {
|
||||
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
|
||||
const provider = web3Factory.create({ rpcUrl: ropstenRpcUrl }).currentProvider;
|
||||
const config = {
|
||||
networkId: constants.ROPSTEN_NETWORK_ID,
|
||||
};
|
||||
|
@@ -95,7 +95,7 @@ describe('EtherTokenWrapper', () => {
|
||||
depositWeiAmount,
|
||||
addressWithETH,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
|
||||
const postETHBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(addressWithETH);
|
||||
const postWETHBalanceInBaseUnits = await contractWrappers.token.getBalanceAsync(
|
||||
@@ -137,7 +137,7 @@ describe('EtherTokenWrapper', () => {
|
||||
depositWeiAmount,
|
||||
addressWithETH,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
|
||||
const postETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH);
|
||||
const postWETHBalanceInBaseUnits = await contractWrappers.token.getBalanceAsync(
|
||||
@@ -347,7 +347,7 @@ describe('EtherTokenWrapper', () => {
|
||||
});
|
||||
it('should get logs with decoded args emitted by Approval', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const eventName = EtherTokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||
@@ -381,7 +381,7 @@ describe('EtherTokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const differentEventName = EtherTokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.etherToken.getLogsAsync(
|
||||
@@ -394,12 +394,12 @@ describe('EtherTokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(
|
||||
etherTokenAddress,
|
||||
addressWithoutFunds,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const eventName = EtherTokenEvents.Approval;
|
||||
const indexFilterValues = {
|
||||
_owner: addressWithETH,
|
||||
|
@@ -60,7 +60,7 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
it("throws if the user doesn't have enough balance", async () => {
|
||||
txHash = await contractWrappers.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
return expect(
|
||||
exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
@@ -74,9 +74,9 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
it('updates balances and proxyAllowance after transfer', async () => {
|
||||
txHash = await contractWrappers.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
txHash = await contractWrappers.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
@@ -95,9 +95,9 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
it("doesn't update proxyAllowance after transfer if unlimited", async () => {
|
||||
txHash = await contractWrappers.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
|
@@ -276,7 +276,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
expect(
|
||||
await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress),
|
||||
).to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
||||
@@ -305,7 +305,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
expect(
|
||||
await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress),
|
||||
).to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
||||
@@ -338,7 +338,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
expect(
|
||||
await contractWrappers.token.getBalanceAsync(zrxTokenAddress, feeRecipient),
|
||||
).to.be.bignumber.equal(makerFee.plus(takerFee));
|
||||
@@ -469,7 +469,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(
|
||||
anotherOrderHashHex,
|
||||
@@ -595,7 +595,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(
|
||||
anotherOrderHashHex,
|
||||
@@ -611,7 +611,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const zeroAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
|
||||
expect(filledAmount).to.be.bignumber.equal(fillableAmount);
|
||||
@@ -632,7 +632,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(
|
||||
anotherOrderHashHex,
|
||||
@@ -730,7 +730,7 @@ describe('ExchangeWrapper', () => {
|
||||
describe('successful cancels', () => {
|
||||
it('should cancel an order', async () => {
|
||||
const txHash = await contractWrappers.exchange.cancelOrderAsync(signedOrder, cancelAmount);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const cancelledAmount = await contractWrappers.exchange.getCancelledTakerAmountAsync(orderHashHex);
|
||||
expect(cancelledAmount).to.be.bignumber.equal(cancelAmount);
|
||||
});
|
||||
@@ -1112,7 +1112,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const eventName = ExchangeEvents.LogFill;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync(eventName, blockRange, indexFilterValues);
|
||||
@@ -1133,7 +1133,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const differentEventName = ExchangeEvents.LogCancel;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync(
|
||||
@@ -1157,7 +1157,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
|
||||
const differentMakerAddress = userAddresses[2];
|
||||
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
@@ -1173,7 +1173,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
|
||||
const eventName = ExchangeEvents.LogFill;
|
||||
const indexFilterValues = {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { runV1MigrationsAsync } from '@0xproject/migrations';
|
||||
import { runMigrationsAsync } from '@0xproject/migrations';
|
||||
import * as path from 'path';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
@@ -11,9 +11,9 @@ before('migrate contracts', async function(): Promise<void> {
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
gas: devConstants.GAS_ESTIMATE,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
const artifactsDir = `../migrations/artifacts/1.0.0`;
|
||||
await runV1MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
await runMigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
});
|
||||
|
@@ -51,34 +51,6 @@ describe('SubscriptionTest', () => {
|
||||
_.each(stubs, s => s.restore());
|
||||
stubs = [];
|
||||
});
|
||||
it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const errMsg = 'Error fetching block';
|
||||
const callback = callbackErrorReporter.assertNodeCallbackError(done, errMsg);
|
||||
stubs = [Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))];
|
||||
contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
coinbase,
|
||||
addressWithoutFunds,
|
||||
allowanceAmount,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should receive the Error when an error occurs while reconciling the new block', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const errMsg = 'Error fetching logs';
|
||||
const callback = callbackErrorReporter.assertNodeCallbackError(done, errMsg);
|
||||
stubs = [Sinon.stub((contractWrappers as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))];
|
||||
contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
coinbase,
|
||||
addressWithoutFunds,
|
||||
allowanceAmount,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
||||
|
@@ -542,7 +542,7 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
it('should get logs with decoded args emitted by Approval', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const eventName = TokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||
@@ -560,7 +560,7 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const differentEventName = TokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.token.getLogsAsync(
|
||||
@@ -573,9 +573,9 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const eventName = TokenEvents.Approval;
|
||||
const indexFilterValues = {
|
||||
_owner: coinbase,
|
||||
|
@@ -2,7 +2,8 @@ import { devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { Provider } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
|
||||
const provider: Provider = web3.currentProvider;
|
||||
const web3Wrapper = new Web3Wrapper(web3.currentProvider);
|
||||
|
||||
export { provider, web3Wrapper };
|
||||
|
@@ -2,11 +2,11 @@
|
||||
* This file is auto-generated using abi-gen. Don't edit directly.
|
||||
* Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates.
|
||||
*/
|
||||
// tslint:disable:no-consecutive-blank-lines ordered-imports
|
||||
// tslint:disable:no-consecutive-blank-lines
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
import { BaseContract } from '@0xproject/base-contract';
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, DataItem, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, DataItem, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from '@0xproject/types';
|
||||
import { BigNumber, classUtils, logUtils, promisify } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as ethers from 'ethers';
|
||||
@@ -31,7 +31,6 @@ export enum {{contractName}}Events {
|
||||
{{/if}}
|
||||
|
||||
// tslint:disable:no-parameter-reassignment
|
||||
// tslint:disable-next-line:class-name
|
||||
export class {{contractName}}Contract extends BaseContract {
|
||||
{{#each methods}}
|
||||
{{#this.constant}}
|
||||
@@ -76,7 +75,7 @@ export class {{contractName}}Contract extends BaseContract {
|
||||
);
|
||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
logUtils.log(`transactionHash: ${txHash}`);
|
||||
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
logUtils.log(`{{contractName}} successfully deployed at ${txReceipt.contractAddress}`);
|
||||
const contractInstance = new {{contractName}}Contract(abi, txReceipt.contractAddress as string, provider, txDefaults);
|
||||
contractInstance.constructorArgs = [{{> params inputs=ctor.inputs}}];
|
||||
|
@@ -1,11 +1,7 @@
|
||||
{
|
||||
"artifactsDir": "../migrations/artifacts/2.0.0",
|
||||
"artifactsDir": "../migrations/artifacts/1.0.0",
|
||||
"contractsDir": "src/contracts",
|
||||
"compilerSettings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 0
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
@@ -19,22 +15,19 @@
|
||||
}
|
||||
},
|
||||
"contracts": [
|
||||
"AssetProxyOwner",
|
||||
"DummyERC20Token",
|
||||
"DummyERC721Token",
|
||||
"ERC20Proxy",
|
||||
"ERC721Proxy",
|
||||
"Exchange",
|
||||
"MixinAuthorizable",
|
||||
"DummyToken",
|
||||
"ZRXToken",
|
||||
"Token",
|
||||
"WETH9",
|
||||
"TokenTransferProxy",
|
||||
"MultiSigWallet",
|
||||
"MultiSigWalletWithTimeLock",
|
||||
"TestAssetProxyDispatcher",
|
||||
"TestLibBytes",
|
||||
"TestLibs",
|
||||
"TestSignatureValidator",
|
||||
"MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress",
|
||||
"MaliciousToken",
|
||||
"TokenRegistry",
|
||||
"Whitelist",
|
||||
"WETH9",
|
||||
"ZRXToken"
|
||||
"Arbitrage",
|
||||
"EtherDelta",
|
||||
"AccountLevels"
|
||||
]
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "contracts",
|
||||
"version": "2.1.29",
|
||||
"version": "2.1.34",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -12,24 +12,24 @@
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean compile copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/2.0.0/**/*' ./lib/src/artifacts;",
|
||||
"prebuild": "run-s clean copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/1.0.0/**/*' ./lib/src/artifacts;",
|
||||
"build": "tsc",
|
||||
"test": "run-s build run_mocha",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846",
|
||||
"compile": "sol-compiler",
|
||||
"clean": "shx rm -rf lib src/contract_wrappers/generated",
|
||||
"generate_contract_wrappers":
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||
"lint": "tslint --project .",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test"
|
||||
"test:circleci": "yarn test:coverage"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
"abis": "../migrations/artifacts/1.0.0/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels|WETH9|MaliciousToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -42,45 +42,40 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^0.3.0",
|
||||
"@0xproject/dev-utils": "^0.4.2",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@0xproject/subproviders": "^0.10.1",
|
||||
"@0xproject/sol-cov": "^0.0.11",
|
||||
"@0xproject/abi-gen": "^0.3.3",
|
||||
"@0xproject/dev-utils": "^0.4.5",
|
||||
"@0xproject/tslint-config": "^0.4.21",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/ethereumjs-abi": "^0.6.0",
|
||||
"@types/yargs": "^10.0.0",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^2.0.1",
|
||||
"copyfiles": "^1.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"solc": "^0.4.24",
|
||||
"@types/node": "9.6.0",
|
||||
"@types/yargs": "10.0.2",
|
||||
"chai": "4.1.2",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chai-bignumber": "2.0.1",
|
||||
"copyfiles": "1.2.0",
|
||||
"dirty-chai": "2.0.1",
|
||||
"make-promises-safe": "1.1.0",
|
||||
"mocha": "4.1.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"prettier": "1.12.1",
|
||||
"shx": "0.2.2",
|
||||
"solc": "0.4.23",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.7.1",
|
||||
"yargs": "^10.0.3"
|
||||
"yargs": "11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/order-utils": "^0.0.5",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereumjs-abi": "^0.6.4",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "^3.0.15",
|
||||
"lodash": "^4.17.4",
|
||||
"web3": "^0.20.0"
|
||||
"0x.js": "^0.38.5",
|
||||
"@0xproject/base-contract": "^0.3.5",
|
||||
"@0xproject/sol-compiler": "^0.5.3",
|
||||
"@0xproject/types": "^0.8.2",
|
||||
"@0xproject/typescript-typings": "^0.4.2",
|
||||
"@0xproject/utils": "^0.7.2",
|
||||
"@0xproject/web3-wrapper": "^0.7.2",
|
||||
"bn.js": "4.11.7",
|
||||
"ethereumjs-abi": "0.6.5",
|
||||
"ethereumjs-util": "5.1.5",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "4.17.10",
|
||||
"web3": "0.20.6"
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
pragma solidity ^0.4.10;
|
||||
|
||||
import "./MultiSigWallet.sol";
|
||||
import { MultiSigWallet } from "../MultiSigWallet/MultiSigWallet.sol";
|
||||
|
||||
/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
pragma solidity ^0.4.10;
|
||||
|
||||
import "../../current/multisig/MultiSigWalletWithTimeLock.sol";
|
||||
import { MultiSigWalletWithTimeLock } from "../MultiSigWalletWithTimeLock/MultiSigWalletWithTimeLock.sol";
|
||||
|
||||
contract MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress is MultiSigWalletWithTimeLock {
|
||||
|
||||
@@ -79,4 +79,4 @@ contract MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress is MultiSigWall
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,87 +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 "../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
||||
import "./MixinAssetProxy.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
|
||||
contract ERC20Proxy is
|
||||
LibBytes,
|
||||
MixinAssetProxy,
|
||||
MixinAuthorizable
|
||||
{
|
||||
|
||||
// Id of this proxy.
|
||||
uint8 constant PROXY_ID = 1;
|
||||
|
||||
// Revert reasons
|
||||
string constant INVALID_METADATA_LENGTH = "Metadata must have a length of 21.";
|
||||
string constant TRANSFER_FAILED = "Transfer failed.";
|
||||
string constant PROXY_ID_MISMATCH = "Proxy id in metadata does not match this proxy id.";
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
uint256 length = assetMetadata.length;
|
||||
|
||||
require(
|
||||
length == 21,
|
||||
INVALID_METADATA_LENGTH
|
||||
);
|
||||
|
||||
require(
|
||||
uint8(assetMetadata[length - 1]) == PROXY_ID,
|
||||
PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// Decode metadata.
|
||||
address token = readAddress(assetMetadata, 0);
|
||||
|
||||
// Transfer tokens.
|
||||
bool success = IERC20Token(token).transferFrom(from, to, amount);
|
||||
require(
|
||||
success == true,
|
||||
TRANSFER_FAILED
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
/// @return Proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
view
|
||||
returns (uint8)
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
}
|
@@ -1,93 +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 "../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../tokens/ERC721Token/ERC721Token.sol";
|
||||
import "./MixinAssetProxy.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
|
||||
contract ERC721Proxy is
|
||||
LibBytes,
|
||||
MixinAssetProxy,
|
||||
MixinAuthorizable
|
||||
{
|
||||
|
||||
// Id of this proxy.
|
||||
uint8 constant PROXY_ID = 2;
|
||||
|
||||
// Revert reasons
|
||||
string constant INVALID_TRANSFER_AMOUNT = "Transfer amount must equal 1.";
|
||||
string constant INVALID_METADATA_LENGTH = "Metadata must have a length of 53.";
|
||||
string constant PROXY_ID_MISMATCH = "Proxy id in metadata does not match this proxy id.";
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
uint256 length = assetMetadata.length;
|
||||
|
||||
require(
|
||||
length == 53,
|
||||
INVALID_METADATA_LENGTH
|
||||
);
|
||||
|
||||
require(
|
||||
uint8(assetMetadata[length - 1]) == PROXY_ID,
|
||||
PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// There exists only 1 of each token.
|
||||
require(
|
||||
amount == 1,
|
||||
INVALID_TRANSFER_AMOUNT
|
||||
);
|
||||
|
||||
// Decode metadata
|
||||
address token = readAddress(assetMetadata, 0);
|
||||
uint256 tokenId = readUint256(assetMetadata, 20);
|
||||
|
||||
// Transfer token.
|
||||
// Either succeeds or throws.
|
||||
// @TODO: Call safeTransferFrom if there is additional
|
||||
// data stored in `assetMetadata`.
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
/// @return Proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
view
|
||||
returns (uint8)
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
}
|
@@ -1,75 +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 "./mixins/MAssetProxy.sol";
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
|
||||
contract MixinAssetProxy is
|
||||
MAuthorizable,
|
||||
MAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyAuthorized
|
||||
{
|
||||
transferFromInternal(
|
||||
assetMetadata,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetMetadata,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
for (uint256 i = 0; i < assetMetadata.length; i++) {
|
||||
transferFromInternal(
|
||||
assetMetadata[i],
|
||||
from[i],
|
||||
to[i],
|
||||
amounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,120 +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 "./mixins/MAuthorizable.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
|
||||
contract MixinAuthorizable is
|
||||
Ownable,
|
||||
MAuthorizable
|
||||
{
|
||||
|
||||
// Revert reasons
|
||||
string constant SENDER_NOT_AUTHORIZED = "Sender not authorized to call this method.";
|
||||
string constant TARGET_NOT_AUTHORIZED = "Target address must be authorized.";
|
||||
string constant TARGET_ALREADY_AUTHORIZED = "Target must not already be authorized.";
|
||||
string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
|
||||
string constant INDEX_ADDRESS_MISMATCH = "Address found at index does not match target address.";
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized {
|
||||
require(
|
||||
authorized[msg.sender],
|
||||
SENDER_NOT_AUTHORIZED
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
mapping (address => bool) public authorized;
|
||||
address[] public authorities;
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
!authorized[target],
|
||||
TARGET_ALREADY_AUTHORIZED
|
||||
);
|
||||
|
||||
authorized[target] = true;
|
||||
authorities.push(target);
|
||||
emit AuthorizedAddressAdded(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
function removeAuthorizedAddress(address target)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
authorized[target],
|
||||
TARGET_NOT_AUTHORIZED
|
||||
);
|
||||
|
||||
delete authorized[target];
|
||||
for (uint i = 0; i < authorities.length; i++) {
|
||||
if (authorities[i] == target) {
|
||||
authorities[i] = authorities[authorities.length - 1];
|
||||
authorities.length -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit AuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
/// @param index Index of target in authorities array.
|
||||
function removeAuthorizedAddressAtIndex(
|
||||
address target,
|
||||
uint256 index
|
||||
)
|
||||
external
|
||||
{
|
||||
require(
|
||||
index < authorities.length,
|
||||
INDEX_OUT_OF_BOUNDS
|
||||
);
|
||||
require(
|
||||
authorities[index] == target,
|
||||
INDEX_ADDRESS_MISMATCH
|
||||
);
|
||||
|
||||
delete authorized[target];
|
||||
authorities[index] = authorities[authorities.length - 1];
|
||||
authorities.length -= 1;
|
||||
emit AuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
external
|
||||
view
|
||||
returns (address[] memory)
|
||||
{
|
||||
return authorities;
|
||||
}
|
||||
}
|
@@ -1,61 +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 "./IAuthorizable.sol";
|
||||
|
||||
contract IAssetProxy is
|
||||
IAuthorizable
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetMetadata,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
/// @return Proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
view
|
||||
returns (uint8);
|
||||
}
|
||||
|
@@ -1,53 +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 "../../../utils/Ownable/IOwnable.sol";
|
||||
|
||||
contract IAuthorizable is
|
||||
IOwnable
|
||||
{
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
external
|
||||
view
|
||||
returns (address[]);
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
external;
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
function removeAuthorizedAddress(address target)
|
||||
external;
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
/// @param index Index of target in authorities array.
|
||||
function removeAuthorizedAddressAtIndex(
|
||||
address target,
|
||||
uint256 index
|
||||
)
|
||||
external;
|
||||
}
|
@@ -1,40 +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 "../interfaces/IAssetProxy.sol";
|
||||
|
||||
contract MAssetProxy is
|
||||
IAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -1,42 +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 "../interfaces/IAuthorizable.sol";
|
||||
|
||||
contract MAuthorizable is
|
||||
IAuthorizable
|
||||
{
|
||||
|
||||
// Event logged when a new address is authorized.
|
||||
event AuthorizedAddressAdded(
|
||||
address indexed target,
|
||||
address indexed caller
|
||||
);
|
||||
|
||||
// Event logged when a currently authorized address is unauthorized.
|
||||
event AuthorizedAddressRemoved(
|
||||
address indexed target,
|
||||
address indexed caller
|
||||
);
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized { revert(); _; }
|
||||
}
|
@@ -1,111 +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.10;
|
||||
|
||||
import "../../multisig/MultiSigWalletWithTimeLock.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
|
||||
contract AssetProxyOwner is
|
||||
LibBytes,
|
||||
MultiSigWalletWithTimeLock
|
||||
{
|
||||
|
||||
event AssetProxyRegistration(address assetProxyContract, bool isRegistered);
|
||||
|
||||
// Mapping of AssetProxy contract address =>
|
||||
// if this contract is allowed to call the AssetProxy's removeAuthorizedAddress method without a time lock.
|
||||
mapping (address => bool) public isAssetProxyRegistered;
|
||||
|
||||
bytes4 constant REMOVE_AUTHORIZED_ADDRESS_SELECTOR = bytes4(keccak256("removeAuthorizedAddress(address)"));
|
||||
|
||||
/// @dev Function will revert if the transaction does not call `removeAuthorizedAddress`
|
||||
/// on an approved AssetProxy contract.
|
||||
modifier validRemoveAuthorizedAddressTx(uint256 transactionId) {
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
require(isAssetProxyRegistered[tx.destination]);
|
||||
require(isFunctionRemoveAuthorizedAddress(tx.data));
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Contract constructor sets initial owners, required number of confirmations,
|
||||
/// time lock, and list of AssetProxy addresses.
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _assetProxyContracts Array of AssetProxy contract addresses.
|
||||
/// @param _required Number of required confirmations.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
function AssetProxyOwner(
|
||||
address[] memory _owners,
|
||||
address[] memory _assetProxyContracts,
|
||||
uint256 _required,
|
||||
uint256 _secondsTimeLocked
|
||||
)
|
||||
public
|
||||
MultiSigWalletWithTimeLock(_owners, _required, _secondsTimeLocked)
|
||||
{
|
||||
for (uint256 i = 0; i < _assetProxyContracts.length; i++) {
|
||||
address assetProxy = _assetProxyContracts[i];
|
||||
require(assetProxy != address(0));
|
||||
isAssetProxyRegistered[assetProxy] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Registers or deregisters an AssetProxy to be able to execute
|
||||
/// removeAuthorizedAddress without a timelock.
|
||||
/// @param assetProxyContract Address of AssetProxy contract.
|
||||
/// @param isRegistered Status of approval for AssetProxy contract.
|
||||
function registerAssetProxy(address assetProxyContract, bool isRegistered)
|
||||
public
|
||||
onlyWallet
|
||||
notNull(assetProxyContract)
|
||||
{
|
||||
isAssetProxyRegistered[assetProxyContract] = isRegistered;
|
||||
AssetProxyRegistration(assetProxyContract, isRegistered);
|
||||
}
|
||||
|
||||
/// @dev Allows execution of removeAuthorizedAddress without time lock.
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeRemoveAuthorizedAddress(uint256 transactionId)
|
||||
public
|
||||
notExecuted(transactionId)
|
||||
fullyConfirmed(transactionId)
|
||||
validRemoveAuthorizedAddressTx(transactionId)
|
||||
{
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Compares first 4 bytes of byte array to removeAuthorizedAddress function selector.
|
||||
/// @param data Transaction data.
|
||||
/// @return Successful if data is a call to removeAuthorizedAddress.
|
||||
function isFunctionRemoveAuthorizedAddress(bytes memory data)
|
||||
public
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
bytes4 first4Bytes = readFirst4(data);
|
||||
require(REMOVE_AUTHORIZED_ADDRESS_SELECTOR == first4Bytes);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,38 +16,587 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
pragma solidity ^0.4.14;
|
||||
|
||||
import "./MixinExchangeCore.sol";
|
||||
import "./MixinSignatureValidator.sol";
|
||||
import "./MixinSettlement.sol";
|
||||
import "./MixinWrapperFunctions.sol";
|
||||
import "./MixinAssetProxyDispatcher.sol";
|
||||
import "./MixinTransactions.sol";
|
||||
import "./MixinMatchOrders.sol";
|
||||
import { TokenTransferProxy } from "../TokenTransferProxy/TokenTransferProxy.sol";
|
||||
import { Token_v1 as Token } from "../../../previous/Token/Token_v1.sol";
|
||||
import { SafeMath_v1 as SafeMath } from "../../../previous/SafeMath/SafeMath_v1.sol";
|
||||
|
||||
contract Exchange is
|
||||
MixinExchangeCore,
|
||||
MixinMatchOrders,
|
||||
MixinSettlement,
|
||||
MixinSignatureValidator,
|
||||
MixinTransactions,
|
||||
MixinAssetProxyDispatcher,
|
||||
MixinWrapperFunctions
|
||||
{
|
||||
/// @title Exchange - Facilitates exchange of ERC20 tokens.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
||||
contract Exchange is SafeMath {
|
||||
|
||||
string constant public VERSION = "2.0.1-alpha";
|
||||
// Error Codes
|
||||
enum Errors {
|
||||
ORDER_EXPIRED, // Order has already expired
|
||||
ORDER_FULLY_FILLED_OR_CANCELLED, // Order has already been fully filled or cancelled
|
||||
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
|
||||
INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer
|
||||
}
|
||||
|
||||
// Mixins are instantiated in the order they are inherited
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
string constant public VERSION = "1.0.0";
|
||||
uint16 constant public EXTERNAL_QUERY_GAS_LIMIT = 4999; // Changes to state require at least 5000 gas
|
||||
|
||||
address public ZRX_TOKEN_CONTRACT;
|
||||
address public TOKEN_TRANSFER_PROXY_CONTRACT;
|
||||
|
||||
// Mappings of orderHash => amounts of takerTokenAmount filled or cancelled.
|
||||
mapping (bytes32 => uint) public filled;
|
||||
mapping (bytes32 => uint) public cancelled;
|
||||
|
||||
event LogFill(
|
||||
address indexed maker,
|
||||
address taker,
|
||||
address indexed feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint filledMakerTokenAmount,
|
||||
uint filledTakerTokenAmount,
|
||||
uint paidMakerFee,
|
||||
uint paidTakerFee,
|
||||
bytes32 indexed tokens, // keccak256(makerToken, takerToken), allows subscribing to a token pair
|
||||
bytes32 orderHash
|
||||
);
|
||||
|
||||
event LogCancel(
|
||||
address indexed maker,
|
||||
address indexed feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint cancelledMakerTokenAmount,
|
||||
uint cancelledTakerTokenAmount,
|
||||
bytes32 indexed tokens,
|
||||
bytes32 orderHash
|
||||
);
|
||||
|
||||
event LogError(uint8 indexed errorId, bytes32 indexed orderHash);
|
||||
|
||||
struct Order {
|
||||
address maker;
|
||||
address taker;
|
||||
address makerToken;
|
||||
address takerToken;
|
||||
address feeRecipient;
|
||||
uint makerTokenAmount;
|
||||
uint takerTokenAmount;
|
||||
uint makerFee;
|
||||
uint takerFee;
|
||||
uint expirationTimestampInSec;
|
||||
bytes32 orderHash;
|
||||
}
|
||||
|
||||
function Exchange(address _zrxToken, address _tokenTransferProxy) {
|
||||
ZRX_TOKEN_CONTRACT = _zrxToken;
|
||||
TOKEN_TRANSFER_PROXY_CONTRACT = _tokenTransferProxy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Core exchange functions
|
||||
*/
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfer will fail before attempting.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
/// @return Total amount of takerToken filled in trade.
|
||||
function fillOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
returns (uint filledTakerTokenAmount)
|
||||
{
|
||||
Order memory order = Order({
|
||||
maker: orderAddresses[0],
|
||||
taker: orderAddresses[1],
|
||||
makerToken: orderAddresses[2],
|
||||
takerToken: orderAddresses[3],
|
||||
feeRecipient: orderAddresses[4],
|
||||
makerTokenAmount: orderValues[0],
|
||||
takerTokenAmount: orderValues[1],
|
||||
makerFee: orderValues[2],
|
||||
takerFee: orderValues[3],
|
||||
expirationTimestampInSec: orderValues[4],
|
||||
orderHash: getOrderHash(orderAddresses, orderValues)
|
||||
});
|
||||
|
||||
require(order.taker == address(0) || order.taker == msg.sender);
|
||||
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && fillTakerTokenAmount > 0);
|
||||
require(isValidSignature(
|
||||
order.maker,
|
||||
order.orderHash,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
));
|
||||
|
||||
if (block.timestamp >= order.expirationTimestampInSec) {
|
||||
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
|
||||
filledTakerTokenAmount = min256(fillTakerTokenAmount, remainingTakerTokenAmount);
|
||||
if (filledTakerTokenAmount == 0) {
|
||||
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isRoundingError(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount)) {
|
||||
LogError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!shouldThrowOnInsufficientBalanceOrAllowance && !isTransferable(order, filledTakerTokenAmount)) {
|
||||
LogError(uint8(Errors.INSUFFICIENT_BALANCE_OR_ALLOWANCE), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint filledMakerTokenAmount = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
uint paidMakerFee;
|
||||
uint paidTakerFee;
|
||||
filled[order.orderHash] = safeAdd(filled[order.orderHash], filledTakerTokenAmount);
|
||||
require(transferViaTokenTransferProxy(
|
||||
order.makerToken,
|
||||
order.maker,
|
||||
msg.sender,
|
||||
filledMakerTokenAmount
|
||||
));
|
||||
require(transferViaTokenTransferProxy(
|
||||
order.takerToken,
|
||||
msg.sender,
|
||||
order.maker,
|
||||
filledTakerTokenAmount
|
||||
));
|
||||
if (order.feeRecipient != address(0)) {
|
||||
if (order.makerFee > 0) {
|
||||
paidMakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerFee);
|
||||
require(transferViaTokenTransferProxy(
|
||||
ZRX_TOKEN_CONTRACT,
|
||||
order.maker,
|
||||
order.feeRecipient,
|
||||
paidMakerFee
|
||||
));
|
||||
}
|
||||
if (order.takerFee > 0) {
|
||||
paidTakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.takerFee);
|
||||
require(transferViaTokenTransferProxy(
|
||||
ZRX_TOKEN_CONTRACT,
|
||||
msg.sender,
|
||||
order.feeRecipient,
|
||||
paidTakerFee
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
LogFill(
|
||||
order.maker,
|
||||
msg.sender,
|
||||
order.feeRecipient,
|
||||
order.makerToken,
|
||||
order.takerToken,
|
||||
filledMakerTokenAmount,
|
||||
filledTakerTokenAmount,
|
||||
paidMakerFee,
|
||||
paidTakerFee,
|
||||
keccak256(order.makerToken, order.takerToken),
|
||||
order.orderHash
|
||||
);
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/// @dev Cancels the input order.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param cancelTakerTokenAmount Desired amount of takerToken to cancel in order.
|
||||
/// @return Amount of takerToken cancelled.
|
||||
function cancelOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint cancelTakerTokenAmount)
|
||||
public
|
||||
MixinExchangeCore()
|
||||
MixinMatchOrders()
|
||||
MixinSettlement(_zrxProxyData)
|
||||
MixinSignatureValidator()
|
||||
MixinTransactions()
|
||||
MixinAssetProxyDispatcher()
|
||||
MixinWrapperFunctions()
|
||||
{}
|
||||
returns (uint)
|
||||
{
|
||||
Order memory order = Order({
|
||||
maker: orderAddresses[0],
|
||||
taker: orderAddresses[1],
|
||||
makerToken: orderAddresses[2],
|
||||
takerToken: orderAddresses[3],
|
||||
feeRecipient: orderAddresses[4],
|
||||
makerTokenAmount: orderValues[0],
|
||||
takerTokenAmount: orderValues[1],
|
||||
makerFee: orderValues[2],
|
||||
takerFee: orderValues[3],
|
||||
expirationTimestampInSec: orderValues[4],
|
||||
orderHash: getOrderHash(orderAddresses, orderValues)
|
||||
});
|
||||
|
||||
require(order.maker == msg.sender);
|
||||
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && cancelTakerTokenAmount > 0);
|
||||
|
||||
if (block.timestamp >= order.expirationTimestampInSec) {
|
||||
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
|
||||
uint cancelledTakerTokenAmount = min256(cancelTakerTokenAmount, remainingTakerTokenAmount);
|
||||
if (cancelledTakerTokenAmount == 0) {
|
||||
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cancelled[order.orderHash] = safeAdd(cancelled[order.orderHash], cancelledTakerTokenAmount);
|
||||
|
||||
LogCancel(
|
||||
order.maker,
|
||||
order.feeRecipient,
|
||||
order.makerToken,
|
||||
order.takerToken,
|
||||
getPartialAmount(cancelledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount),
|
||||
cancelledTakerTokenAmount,
|
||||
keccak256(order.makerToken, order.takerToken),
|
||||
order.orderHash
|
||||
);
|
||||
return cancelledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper functions
|
||||
*/
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature, throws if specified amount not filled entirely.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
function fillOrKillOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
{
|
||||
require(fillOrder(
|
||||
orderAddresses,
|
||||
orderValues,
|
||||
fillTakerTokenAmount,
|
||||
false,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
) == fillTakerTokenAmount);
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
function batchFillOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] fillTakerTokenAmounts,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
fillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
fillTakerTokenAmounts[i],
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fillOrKill orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
function batchFillOrKillOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] fillTakerTokenAmounts,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
fillOrKillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
fillTakerTokenAmounts[i],
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total fillTakerTokenAmount filled.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmount Desired total amount of takerToken to fill in orders.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
/// @return Total amount of fillTakerTokenAmount filled in orders.
|
||||
function fillOrdersUpTo(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
returns (uint)
|
||||
{
|
||||
uint filledTakerTokenAmount = 0;
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
require(orderAddresses[i][3] == orderAddresses[0][3]); // takerToken must be the same for each order
|
||||
filledTakerTokenAmount = safeAdd(filledTakerTokenAmount, fillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
safeSub(fillTakerTokenAmount, filledTakerTokenAmount),
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
));
|
||||
if (filledTakerTokenAmount == fillTakerTokenAmount) break;
|
||||
}
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param cancelTakerTokenAmounts Array of desired amounts of takerToken to cancel in orders.
|
||||
function batchCancelOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] cancelTakerTokenAmounts)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
cancelOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
cancelTakerTokenAmounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constant public functions
|
||||
*/
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of order with specified parameters.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @return Keccak-256 hash of order.
|
||||
function getOrderHash(address[5] orderAddresses, uint[6] orderValues)
|
||||
public
|
||||
constant
|
||||
returns (bytes32)
|
||||
{
|
||||
return keccak256(
|
||||
address(this),
|
||||
orderAddresses[0], // maker
|
||||
orderAddresses[1], // taker
|
||||
orderAddresses[2], // makerToken
|
||||
orderAddresses[3], // takerToken
|
||||
orderAddresses[4], // feeRecipient
|
||||
orderValues[0], // makerTokenAmount
|
||||
orderValues[1], // takerTokenAmount
|
||||
orderValues[2], // makerFee
|
||||
orderValues[3], // takerFee
|
||||
orderValues[4], // expirationTimestampInSec
|
||||
orderValues[5] // salt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Verifies that an order signature is valid.
|
||||
/// @param signer address of signer.
|
||||
/// @param hash Signed Keccak-256 hash.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
address signer,
|
||||
bytes32 hash,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
return signer == ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n32", hash),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingError(uint numerator, uint denominator, uint target)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
uint remainder = mulmod(target, numerator, denominator);
|
||||
if (remainder == 0) return false; // No rounding error.
|
||||
|
||||
uint errPercentageTimes1000000 = safeDiv(
|
||||
safeMul(remainder, 1000000),
|
||||
safeMul(numerator, target)
|
||||
);
|
||||
return errPercentageTimes1000000 > 1000;
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmount(uint numerator, uint denominator, uint target)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
return safeDiv(safeMul(numerator, target), denominator);
|
||||
}
|
||||
|
||||
/// @dev Calculates the sum of values already filled and cancelled for a given order.
|
||||
/// @param orderHash The Keccak-256 hash of the given order.
|
||||
/// @return Sum of values already filled and cancelled.
|
||||
function getUnavailableTakerTokenAmount(bytes32 orderHash)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
return safeAdd(filled[orderHash], cancelled[orderHash]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Internal functions
|
||||
*/
|
||||
|
||||
/// @dev Transfers a token using TokenTransferProxy transferFrom function.
|
||||
/// @param token Address of token to transferFrom.
|
||||
/// @param from Address transfering token.
|
||||
/// @param to Address receiving token.
|
||||
/// @param value Amount of token to transfer.
|
||||
/// @return Success of token transfer.
|
||||
function transferViaTokenTransferProxy(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint value)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
return TokenTransferProxy(TOKEN_TRANSFER_PROXY_CONTRACT).transferFrom(token, from, to, value);
|
||||
}
|
||||
|
||||
/// @dev Checks if any order transfers will fail.
|
||||
/// @param order Order struct of params that will be checked.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @return Predicted result of transfers.
|
||||
function isTransferable(Order order, uint fillTakerTokenAmount)
|
||||
internal
|
||||
constant // The called token contracts may attempt to change state, but will not be able to due to gas limits on getBalance and getAllowance.
|
||||
returns (bool)
|
||||
{
|
||||
address taker = msg.sender;
|
||||
uint fillMakerTokenAmount = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
|
||||
if (order.feeRecipient != address(0)) {
|
||||
bool isMakerTokenZRX = order.makerToken == ZRX_TOKEN_CONTRACT;
|
||||
bool isTakerTokenZRX = order.takerToken == ZRX_TOKEN_CONTRACT;
|
||||
uint paidMakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerFee);
|
||||
uint paidTakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.takerFee);
|
||||
uint requiredMakerZRX = isMakerTokenZRX ? safeAdd(fillMakerTokenAmount, paidMakerFee) : paidMakerFee;
|
||||
uint requiredTakerZRX = isTakerTokenZRX ? safeAdd(fillTakerTokenAmount, paidTakerFee) : paidTakerFee;
|
||||
|
||||
if ( getBalance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX
|
||||
|| getAllowance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX
|
||||
|| getBalance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX
|
||||
|| getAllowance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX
|
||||
) return false;
|
||||
|
||||
if (!isMakerTokenZRX && ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount // Don't double check makerToken if ZRX
|
||||
|| getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount)
|
||||
) return false;
|
||||
if (!isTakerTokenZRX && ( getBalance(order.takerToken, taker) < fillTakerTokenAmount // Don't double check takerToken if ZRX
|
||||
|| getAllowance(order.takerToken, taker) < fillTakerTokenAmount)
|
||||
) return false;
|
||||
} else if ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount
|
||||
|| getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount
|
||||
|| getBalance(order.takerToken, taker) < fillTakerTokenAmount
|
||||
|| getAllowance(order.takerToken, taker) < fillTakerTokenAmount
|
||||
) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Get token balance of an address.
|
||||
/// @param token Address of token.
|
||||
/// @param owner Address of owner.
|
||||
/// @return Token balance of owner.
|
||||
function getBalance(address token, address owner)
|
||||
internal
|
||||
constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit.
|
||||
returns (uint)
|
||||
{
|
||||
return Token(token).balanceOf.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner); // Limit gas to prevent reentrancy
|
||||
}
|
||||
|
||||
/// @dev Get allowance of token given to TokenTransferProxy by an address.
|
||||
/// @param token Address of token.
|
||||
/// @param owner Address of owner.
|
||||
/// @return Allowance of token given to TokenTransferProxy by owner.
|
||||
function getAllowance(address token, address owner)
|
||||
internal
|
||||
constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit.
|
||||
returns (uint)
|
||||
{
|
||||
return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy
|
||||
}
|
||||
}
|
||||
|
@@ -1,110 +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 "../../utils/Ownable/Ownable.sol";
|
||||
import "../AssetProxy/interfaces/IAssetProxy.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
|
||||
contract MixinAssetProxyDispatcher is
|
||||
LibExchangeErrors,
|
||||
Ownable,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
||||
mapping (uint8 => IAssetProxy) public assetProxies;
|
||||
|
||||
/// @dev Registers an asset proxy to an asset proxy id.
|
||||
/// An id can only be assigned to a single proxy at a given time.
|
||||
/// @param assetProxyId Id to register`newAssetProxy` under.
|
||||
/// @param newAssetProxy Address of new asset proxy to register, or 0x0 to unset assetProxyId.
|
||||
/// @param oldAssetProxy Existing asset proxy to overwrite, or 0x0 if assetProxyId is currently unused.
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
// Ensure the existing asset proxy is not unintentionally overwritten
|
||||
require(
|
||||
oldAssetProxy == address(assetProxies[assetProxyId]),
|
||||
OLD_ASSET_PROXY_MISMATCH
|
||||
);
|
||||
|
||||
IAssetProxy assetProxy = IAssetProxy(newAssetProxy);
|
||||
|
||||
// Ensure that the id of newAssetProxy matches the passed in assetProxyId, unless it is being reset to 0.
|
||||
if (newAssetProxy != address(0)) {
|
||||
uint8 newAssetProxyId = assetProxy.getProxyId();
|
||||
require(
|
||||
newAssetProxyId == assetProxyId,
|
||||
NEW_ASSET_PROXY_MISMATCH
|
||||
);
|
||||
}
|
||||
|
||||
// Add asset proxy and log registration.
|
||||
assetProxies[assetProxyId] = assetProxy;
|
||||
emit AssetProxySet(assetProxyId, newAssetProxy, oldAssetProxy);
|
||||
}
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
|
||||
function getAssetProxy(uint8 assetProxyId)
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
address assetProxy = address(assetProxies[assetProxyId]);
|
||||
return assetProxy;
|
||||
}
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Do nothing if no amount should be transferred.
|
||||
if (amount > 0) {
|
||||
|
||||
// Lookup asset proxy
|
||||
uint256 length = assetMetadata.length;
|
||||
require(
|
||||
length > 0,
|
||||
GT_ZERO_LENGTH_REQUIRED
|
||||
);
|
||||
uint8 assetProxyId = uint8(assetMetadata[length - 1]);
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetMetadata, from, to, amount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,446 +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 "./libs/LibFillResults.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibStatus.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
|
||||
contract MixinExchangeCore is
|
||||
SafeMath,
|
||||
LibMath,
|
||||
LibStatus,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore,
|
||||
MSettlement,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
// Mapping of orderHash => amount of takerAsset already bought by maker
|
||||
mapping (bytes32 => uint256) public filled;
|
||||
|
||||
// Mapping of orderHash => cancelled
|
||||
mapping (bytes32 => bool) public cancelled;
|
||||
|
||||
// Mapping of makerAddress => lowest salt an order can have in order to be fillable
|
||||
// Orders with a salt less than their maker's epoch are considered cancelled
|
||||
mapping (address => uint256) public makerEpoch;
|
||||
|
||||
////// Core exchange functions //////
|
||||
|
||||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
|
||||
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 salt)
|
||||
external
|
||||
{
|
||||
uint256 newMakerEpoch = salt + 1; // makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
|
||||
require(
|
||||
newMakerEpoch > makerEpoch[msg.sender], // epoch must be monotonically increasing
|
||||
INVALID_NEW_MAKER_EPOCH
|
||||
);
|
||||
makerEpoch[msg.sender] = newMakerEpoch;
|
||||
emit CancelUpTo(msg.sender, newMakerEpoch);
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrder(
|
||||
Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// Fetch order info
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Either our context is valid or we revert
|
||||
assertValidFill(
|
||||
order,
|
||||
orderInfo.orderStatus,
|
||||
orderInfo.orderHash,
|
||||
takerAddress,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
uint8 status;
|
||||
(status, fillResults) = calculateFillResults(
|
||||
order,
|
||||
orderInfo.orderStatus,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
takerAssetFillAmount
|
||||
);
|
||||
if (status != uint8(Status.SUCCESS)) {
|
||||
emit ExchangeStatus(uint8(status), orderInfo.orderHash);
|
||||
return getNullFillResults();
|
||||
}
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, fillResults);
|
||||
|
||||
// Update exchange internal state
|
||||
updateFilledState(
|
||||
order,
|
||||
takerAddress,
|
||||
orderInfo.orderHash,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
fillResults
|
||||
);
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev After calling, the order can not be filled anymore.
|
||||
/// Throws if order is invalid or sender does not have permission to cancel.
|
||||
/// @param order Order to cancel. Order must be Status.FILLABLE.
|
||||
/// @return True if the order state changed to cancelled.
|
||||
/// False if the order was valid, but in an
|
||||
/// unfillable state (see LibStatus.STATUS for order states)
|
||||
function cancelOrder(Order memory order)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
// Fetch current order status
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
|
||||
// Validate context
|
||||
assertValidCancel(order, orderInfo.orderStatus, orderInfo.orderHash);
|
||||
|
||||
// Perform cancel
|
||||
return updateCancelledState(order, orderInfo.orderStatus, orderInfo.orderHash);
|
||||
}
|
||||
|
||||
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||
/// @param order Order to gather information on.
|
||||
/// @return OrderInfo Information about the order and its state.
|
||||
/// See LibOrder.OrderInfo for a complete description.
|
||||
function getOrderInfo(Order memory order)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo memory orderInfo)
|
||||
{
|
||||
// Compute the order hash
|
||||
orderInfo.orderHash = getOrderHash(order);
|
||||
|
||||
// If order.makerAssetAmount is zero, we also reject the order.
|
||||
// While the Exchange contract handles them correctly, they create
|
||||
// edge cases in the supporting infrastructure because they have
|
||||
// an 'infinite' price when computed by a simple division.
|
||||
if (order.makerAssetAmount == 0) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// If order.takerAssetAmount is zero, then the order will always
|
||||
// be considered filled because 0 == takerAssetAmount == orderTakerAssetFilledAmount
|
||||
// Instead of distinguishing between unfilled and filled zero taker
|
||||
// amount orders, we choose not to support them.
|
||||
if (order.takerAssetAmount == 0) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Validate order expiration
|
||||
if (block.timestamp >= order.expirationTimeSeconds) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_EXPIRED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Check if order has been cancelled
|
||||
if (cancelled[orderInfo.orderHash]) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_CANCELLED);
|
||||
return orderInfo;
|
||||
}
|
||||
if (makerEpoch[order.makerAddress] > order.salt) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_CANCELLED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Fetch filled amount and validate order availability
|
||||
orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash];
|
||||
if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_FULLY_FILLED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// All other statuses are ruled out: order is Fillable
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_FILLABLE);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param orderStatus Status of order to be filled.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
Order memory order,
|
||||
uint8 orderStatus,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
uint256 takerAssetFillAmount
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
uint8 status,
|
||||
FillResults memory fillResults
|
||||
)
|
||||
{
|
||||
// Fill amount must be greater than 0
|
||||
if (takerAssetFillAmount == 0) {
|
||||
status = uint8(Status.TAKER_ASSET_FILL_AMOUNT_TOO_LOW);
|
||||
return (status, fillResults);
|
||||
}
|
||||
|
||||
// Ensure the order is fillable
|
||||
if (orderStatus != uint8(Status.ORDER_FILLABLE)) {
|
||||
status = orderStatus;
|
||||
return (status, fillResults);
|
||||
}
|
||||
|
||||
// Compute takerAssetFilledAmount
|
||||
uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderTakerAssetFilledAmount);
|
||||
uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Validate fill order rounding
|
||||
if (isRoundingError(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount))
|
||||
{
|
||||
status = uint8(Status.ROUNDING_ERROR_TOO_LARGE);
|
||||
return (status, fillResults);
|
||||
}
|
||||
|
||||
// Compute proportional transfer amounts
|
||||
// TODO: All three are multiplied by the same fraction. This can
|
||||
// potentially be optimized.
|
||||
fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
|
||||
fillResults.makerAssetFilledAmount = getPartialAmount(
|
||||
fillResults.takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
);
|
||||
fillResults.makerFeePaid = getPartialAmount(
|
||||
fillResults.takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerFee
|
||||
);
|
||||
fillResults.takerFeePaid = getPartialAmount(
|
||||
fillResults.takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.takerFee
|
||||
);
|
||||
|
||||
status = uint8(Status.SUCCESS);
|
||||
return (status, fillResults);
|
||||
}
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderStatus Status of order to be filled.
|
||||
/// @param orderHash Hash of order to be filled.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
Order memory order,
|
||||
uint8 orderStatus,
|
||||
bytes32 orderHash,
|
||||
address takerAddress,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Ensure order is valid
|
||||
// An order can only be filled if its status is FILLABLE;
|
||||
// however, only invalid statuses result in a throw.
|
||||
// See LibStatus for a complete description of order statuses.
|
||||
require(
|
||||
orderStatus != uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT),
|
||||
INVALID_ORDER_MAKER_ASSET_AMOUNT
|
||||
);
|
||||
require(
|
||||
orderStatus != uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT),
|
||||
INVALID_ORDER_TAKER_ASSET_AMOUNT
|
||||
);
|
||||
|
||||
// Validate Maker signature (check only if first time seen)
|
||||
if (orderTakerAssetFilledAmount == 0) {
|
||||
require(
|
||||
isValidSignature(orderHash, order.makerAddress, signature),
|
||||
SIGNATURE_VALIDATION_FAILED
|
||||
);
|
||||
}
|
||||
|
||||
// Validate sender is allowed to fill this order
|
||||
if (order.senderAddress != address(0)) {
|
||||
require(
|
||||
order.senderAddress == msg.sender,
|
||||
INVALID_SENDER
|
||||
);
|
||||
}
|
||||
|
||||
// Validate taker is allowed to fill this order
|
||||
if (order.takerAddress != address(0)) {
|
||||
require(
|
||||
order.takerAddress == takerAddress,
|
||||
INVALID_CONTEXT
|
||||
);
|
||||
}
|
||||
require(
|
||||
takerAssetFillAmount > 0,
|
||||
GT_ZERO_AMOUNT_REQUIRED
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function updateFilledState(
|
||||
Order memory order,
|
||||
address takerAddress,
|
||||
bytes32 orderHash,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
FillResults memory fillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Update state
|
||||
filled[orderHash] = safeAdd(orderTakerAssetFilledAmount, fillResults.takerAssetFilledAmount);
|
||||
|
||||
// Log order
|
||||
emit Fill(
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerAssetFilledAmount,
|
||||
fillResults.takerAssetFilledAmount,
|
||||
fillResults.makerFeePaid,
|
||||
fillResults.takerFeePaid,
|
||||
orderHash,
|
||||
order.makerAssetData,
|
||||
order.takerAssetData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order that was cancelled.
|
||||
/// @param orderStatus Status of order that was cancelled.
|
||||
/// @param orderHash Hash of order that was cancelled.
|
||||
function assertValidCancel(
|
||||
Order memory order,
|
||||
uint8 orderStatus,
|
||||
bytes32 orderHash
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Ensure order is valid
|
||||
// An order can only be cancelled if its status is FILLABLE;
|
||||
// however, only invalid statuses result in a throw.
|
||||
// See LibStatus for a complete description of order statuses.
|
||||
require(
|
||||
orderStatus != uint8(Status.ORDER_INVALID_MAKER_ASSET_AMOUNT),
|
||||
INVALID_ORDER_MAKER_ASSET_AMOUNT
|
||||
);
|
||||
require(
|
||||
orderStatus != uint8(Status.ORDER_INVALID_TAKER_ASSET_AMOUNT),
|
||||
INVALID_ORDER_TAKER_ASSET_AMOUNT
|
||||
);
|
||||
|
||||
// Validate transaction signed by maker
|
||||
address makerAddress = getCurrentContextAddress();
|
||||
require(
|
||||
order.makerAddress == makerAddress,
|
||||
INVALID_CONTEXT
|
||||
);
|
||||
|
||||
// Validate sender is allowed to cancel this order
|
||||
if (order.senderAddress != address(0)) {
|
||||
require(
|
||||
order.senderAddress == msg.sender,
|
||||
INVALID_SENDER
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of cancelling an order.
|
||||
/// State is only updated if the order is currently fillable.
|
||||
/// Otherwise, updating state would have no effect.
|
||||
/// @param order that was cancelled.
|
||||
/// @param orderStatus Status of order that was cancelled.
|
||||
/// @param orderHash Hash of order that was cancelled.
|
||||
/// @return stateUpdated Returns true only if state was updated.
|
||||
function updateCancelledState(
|
||||
Order memory order,
|
||||
uint8 orderStatus,
|
||||
bytes32 orderHash
|
||||
)
|
||||
internal
|
||||
returns (bool stateUpdated)
|
||||
{
|
||||
// Ensure order is fillable (otherwise cancelling does nothing)
|
||||
// See LibStatus for a complete description of order statuses.
|
||||
if (orderStatus != uint8(Status.ORDER_FILLABLE)) {
|
||||
emit ExchangeStatus(uint8(orderStatus), orderHash);
|
||||
stateUpdated = false;
|
||||
return stateUpdated;
|
||||
}
|
||||
|
||||
// Perform cancel
|
||||
cancelled[orderHash] = true;
|
||||
stateUpdated = true;
|
||||
|
||||
// Log cancel
|
||||
emit Cancel(
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
orderHash,
|
||||
order.makerAssetData,
|
||||
order.takerAssetData
|
||||
);
|
||||
|
||||
return stateUpdated;
|
||||
}
|
||||
}
|
@@ -1,297 +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 "./mixins/MExchangeCore.sol";
|
||||
import "./mixins/MMatchOrders.sol";
|
||||
import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "../../utils/SafeMath/SafeMath.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibStatus.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
|
||||
contract MixinMatchOrders is
|
||||
SafeMath,
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibStatus,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore,
|
||||
MMatchOrders,
|
||||
MSettlement,
|
||||
MTransactions
|
||||
{
|
||||
|
||||
/// @dev Match two complementary orders that have a profitable spread.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the left order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftSignature Proof that order was created by the left maker.
|
||||
/// @param rightSignature Proof that order was created by the right maker.
|
||||
/// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
|
||||
/// TODO: Make this function external once supported by Solidity (See Solidity Issues #3199, #1603)
|
||||
function matchOrders(
|
||||
Order memory leftOrder,
|
||||
Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
returns (MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// Get left & right order info
|
||||
OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
|
||||
OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Either our context is valid or we revert
|
||||
assertValidMatch(leftOrder, rightOrder);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
matchedFillResults = calculateMatchedFillResults(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
leftOrderInfo.orderStatus,
|
||||
rightOrderInfo.orderStatus,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Validate fill contexts
|
||||
assertValidFill(
|
||||
leftOrder,
|
||||
leftOrderInfo.orderStatus,
|
||||
leftOrderInfo.orderHash,
|
||||
takerAddress,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
leftSignature
|
||||
);
|
||||
assertValidFill(
|
||||
rightOrder,
|
||||
rightOrderInfo.orderStatus,
|
||||
rightOrderInfo.orderHash,
|
||||
takerAddress,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
rightSignature
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
// Update exchange state
|
||||
updateFilledState(
|
||||
leftOrder,
|
||||
takerAddress,
|
||||
leftOrderInfo.orderHash,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.left
|
||||
);
|
||||
updateFilledState(
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
rightOrderInfo.orderHash,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right
|
||||
);
|
||||
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
/// @dev Validates context for matchOrders. Succeeds or throws.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function assertValidMatch(
|
||||
Order memory leftOrder,
|
||||
Order memory rightOrder
|
||||
)
|
||||
internal
|
||||
{
|
||||
// The leftOrder maker asset must be the same as the rightOrder taker asset.
|
||||
// TODO: Can we safely assume equality and expect a later failure otherwise?
|
||||
require(
|
||||
areBytesEqual(leftOrder.makerAssetData, rightOrder.takerAssetData),
|
||||
ASSET_MISMATCH_MAKER_TAKER
|
||||
);
|
||||
|
||||
// The leftOrder taker asset must be the same as the rightOrder maker asset.
|
||||
// TODO: Can we safely assume equality and expect a later failure otherwise?
|
||||
require(
|
||||
areBytesEqual(leftOrder.takerAssetData, rightOrder.makerAssetData),
|
||||
ASSET_MISMATCH_TAKER_MAKER
|
||||
);
|
||||
|
||||
// Make sure there is a profitable spread.
|
||||
// There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
|
||||
// than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
|
||||
// This is satisfied by the equations below:
|
||||
// <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
|
||||
// AND
|
||||
// <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
|
||||
// These equations can be combined to get the following:
|
||||
require(
|
||||
safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
|
||||
safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
|
||||
NEGATIVE_SPREAD
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Validates matched fill results. Succeeds or throws.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function assertValidMatchResults(MatchedFillResults memory matchedFillResults)
|
||||
internal
|
||||
{
|
||||
// If the amount transferred from the left order is different than what is transferred, it is a rounding error amount.
|
||||
// Ensure this difference is negligible by dividing the values with each other. The result should equal to ~1.
|
||||
uint256 amountSpentByLeft = safeAdd(
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
matchedFillResults.takerFillAmount
|
||||
);
|
||||
require(
|
||||
!isRoundingError(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
amountSpentByLeft,
|
||||
1
|
||||
),
|
||||
ROUNDING_ERROR_TRANSFER_AMOUNTS
|
||||
);
|
||||
|
||||
// If the amount transferred from the right order is different than what is transferred, it is a rounding error amount.
|
||||
// Ensure this difference is negligible by dividing the values with each other. The result should equal to ~1.
|
||||
require(
|
||||
!isRoundingError(
|
||||
matchedFillResults.right.makerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
1
|
||||
),
|
||||
ROUNDING_ERROR_TRANSFER_AMOUNTS
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the leftOrder order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftOrderStatus Order status of left order.
|
||||
/// @param rightOrderStatus Order status of right order.
|
||||
/// @param leftOrderFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderFilledAmount Amount of right order already filled.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function calculateMatchedFillResults(
|
||||
Order memory leftOrder,
|
||||
Order memory rightOrder,
|
||||
uint8 leftOrderStatus,
|
||||
uint8 rightOrderStatus,
|
||||
uint256 leftOrderFilledAmount,
|
||||
uint256 rightOrderFilledAmount
|
||||
)
|
||||
internal
|
||||
returns (MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We settle orders at the exchange rate of the right order.
|
||||
// The amount saved by the left maker goes to the taker.
|
||||
// Either the left or right order will be fully filled; possibly both.
|
||||
// The left order is fully filled iff the right order can sell more than left can buy.
|
||||
// That is: the amount required to fill the left order is less than or equal to
|
||||
// the amount we can spend from the right order:
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio>
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount>
|
||||
// <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount>
|
||||
uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderFilledAmount);
|
||||
uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderFilledAmount);
|
||||
uint256 leftOrderAmountToFill;
|
||||
uint256 rightOrderAmountToFill;
|
||||
if (
|
||||
safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
|
||||
safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
|
||||
) {
|
||||
// Left order will be fully filled: maximally fill left
|
||||
leftOrderAmountToFill = leftTakerAssetAmountRemaining;
|
||||
|
||||
// The right order receives an amount proportional to how much was spent.
|
||||
// TODO: Can we ensure rounding error is in the correct direction?
|
||||
rightOrderAmountToFill = safeGetPartialAmount(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
leftOrderAmountToFill
|
||||
);
|
||||
} else {
|
||||
// Right order will be fully filled: maximally fill right
|
||||
rightOrderAmountToFill = rightTakerAssetAmountRemaining;
|
||||
|
||||
// The left order receives an amount proportional to how much was spent.
|
||||
// TODO: Can we ensure rounding error is in the correct direction?
|
||||
leftOrderAmountToFill = safeGetPartialAmount(
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrderAmountToFill
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate fill results for left order
|
||||
uint8 status;
|
||||
(status, matchedFillResults.left) = calculateFillResults(
|
||||
leftOrder,
|
||||
leftOrderStatus,
|
||||
leftOrderFilledAmount,
|
||||
leftOrderAmountToFill
|
||||
);
|
||||
require(
|
||||
status == uint8(Status.SUCCESS),
|
||||
FAILED_TO_CALCULATE_FILL_RESULTS_FOR_LEFT_ORDER
|
||||
);
|
||||
|
||||
// Calculate fill results for right order
|
||||
(status, matchedFillResults.right) = calculateFillResults(
|
||||
rightOrder,
|
||||
rightOrderStatus,
|
||||
rightOrderFilledAmount,
|
||||
rightOrderAmountToFill
|
||||
);
|
||||
require(
|
||||
status == uint8(Status.SUCCESS),
|
||||
FAILED_TO_CALCULATE_FILL_RESULTS_FOR_RIGHT_ORDER
|
||||
);
|
||||
|
||||
// Calculate amount given to taker
|
||||
matchedFillResults.takerFillAmount = safeSub(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Validate the fill results
|
||||
assertValidMatchResults(matchedFillResults);
|
||||
|
||||
// Return fill results
|
||||
return matchedFillResults;
|
||||
}
|
||||
}
|
@@ -1,171 +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 "./mixins/MSettlement.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./mixins/MMatchOrders.sol";
|
||||
|
||||
contract MixinSettlement is
|
||||
LibMath,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MMatchOrders,
|
||||
MSettlement,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// ZRX metadata used for fee transfers.
|
||||
// This will be constant throughout the life of the Exchange contract,
|
||||
// since ZRX will always be transferred via the ERC20 AssetProxy.
|
||||
bytes internal ZRX_PROXY_DATA;
|
||||
|
||||
/// @dev Gets the ZRX metadata used for fee transfers.
|
||||
function zrxProxyData()
|
||||
external
|
||||
view
|
||||
returns (bytes memory)
|
||||
{
|
||||
return ZRX_PROXY_DATA;
|
||||
}
|
||||
|
||||
/// TODO: _zrxProxyData should be a constant in production.
|
||||
/// @dev Constructor sets the metadata that will be used for paying ZRX fees.
|
||||
/// @param _zrxProxyData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
public
|
||||
{
|
||||
ZRX_PROXY_DATA = _zrxProxyData;
|
||||
}
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAddress Address selling takerAsset and buying makerAsset.
|
||||
/// @param fillResults Amounts to be filled and fees paid by maker and taker.
|
||||
function settleOrder(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
FillResults memory fillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
dispatchTransferFrom(
|
||||
order.makerAssetData,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
fillResults.makerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
order.takerAssetData,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
fillResults.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.takerFeePaid
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
|
||||
/// @param leftOrder First matched order.
|
||||
/// @param rightOrder Second matched order.
|
||||
/// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
|
||||
/// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
|
||||
function settleMatchedOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
address takerAddress,
|
||||
MatchedFillResults memory matchedFillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Order makers and taker
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftOrder.makerAddress,
|
||||
rightOrder.makerAddress,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
rightOrder.makerAssetData,
|
||||
rightOrder.makerAddress,
|
||||
leftOrder.makerAddress,
|
||||
matchedFillResults.left.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftOrder.makerAddress,
|
||||
takerAddress,
|
||||
matchedFillResults.takerFillAmount
|
||||
);
|
||||
|
||||
// Maker fees
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
leftOrder.makerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
rightOrder.makerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.makerFeePaid
|
||||
);
|
||||
|
||||
// Taker fees
|
||||
if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
safeAdd(
|
||||
matchedFillResults.left.takerFeePaid,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
)
|
||||
);
|
||||
} else {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.takerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
takerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,238 +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 "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "./interfaces/IWallet.sol";
|
||||
import "./interfaces/IValidator.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
|
||||
contract MixinSignatureValidator is
|
||||
LibBytes,
|
||||
LibExchangeErrors,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
|
||||
// Mapping of hash => signer => signed
|
||||
mapping (bytes32 => mapping (address => bool)) public preSigned;
|
||||
|
||||
// Mapping of signer => validator => approved
|
||||
mapping (address => mapping (address => bool)) public allowedValidators;
|
||||
|
||||
/// @dev Approves a hash on-chain using any valid signature type.
|
||||
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
function preSign(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
{
|
||||
require(
|
||||
isValidSignature(hash, signer, signature),
|
||||
SIGNATURE_VALIDATION_FAILED
|
||||
);
|
||||
preSigned[hash][signer] = true;
|
||||
}
|
||||
|
||||
/// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
|
||||
/// @param validator Address of Validator contract.
|
||||
/// @param approval Approval or disapproval of Validator contract.
|
||||
function setSignatureValidatorApproval(
|
||||
address validator,
|
||||
bool approval
|
||||
)
|
||||
external
|
||||
{
|
||||
address signer = getCurrentContextAddress();
|
||||
allowedValidators[signer][validator] = approval;
|
||||
}
|
||||
|
||||
/// @dev Verifies that a hash has been signed by the given signer.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if the address recovered from the provided signature matches the input signer address.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
// TODO: Domain separation: make hash depend on role. (Taker sig should not be valid as maker sig, etc.)
|
||||
require(
|
||||
signature.length >= 1,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
|
||||
// Pop last byte off of signature byte array.
|
||||
SignatureType signatureType = SignatureType(uint8(popByte(signature)));
|
||||
|
||||
// Variables are not scoped in Solidity.
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
address recovered;
|
||||
|
||||
// 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(ILLEGAL_SIGNATURE_TYPE);
|
||||
|
||||
// Always invalid signature.
|
||||
// Like Illegal, this is always implicitly available and therefore
|
||||
// offered explicitly. It can be implicitly created by providing
|
||||
// a correctly formatted but incorrect signature.
|
||||
} else if (signatureType == SignatureType.Invalid) {
|
||||
require(
|
||||
signature.length == 0,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
isValid = false;
|
||||
return isValid;
|
||||
|
||||
// Signature using EIP712
|
||||
} else if (signatureType == SignatureType.EIP712) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(hash, v, r, s);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Signed using web3.eth_sign
|
||||
} else if (signatureType == SignatureType.EthSign) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n32", hash),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Implicitly signed by caller.
|
||||
// The signer has initiated the call. In the case of non-contract
|
||||
// accounts it means the transaction itself was signed.
|
||||
// Example: let's say for a particular operation three signatures
|
||||
// A, B and C are required. To submit the transaction, A and B can
|
||||
// give a signature to C, who can then submit the transaction using
|
||||
// `Caller` for his own signature. Or A and C can sign and B can
|
||||
// submit using `Caller`. Having `Caller` allows this flexibility.
|
||||
} else if (signatureType == SignatureType.Caller) {
|
||||
require(
|
||||
signature.length == 0,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
isValid = signer == msg.sender;
|
||||
return isValid;
|
||||
|
||||
// Signature verified by wallet contract.
|
||||
// If used with an order, the maker of the order is the wallet contract.
|
||||
} else if (signatureType == SignatureType.Wallet) {
|
||||
isValid = IWallet(signer).isValidSignature(hash, signature);
|
||||
return isValid;
|
||||
|
||||
// Signature verified by validator contract.
|
||||
// If used with an order, the maker of the order can still be an EOA.
|
||||
// A signature using this type should be encoded as:
|
||||
// | Offset | Length | Contents |
|
||||
// | 0x00 | x | Signature to validate |
|
||||
// | 0x00 + x | 20 | Address of validator contract |
|
||||
// | 0x14 + x | 1 | Signature type is always "\x06" |
|
||||
} else if (signatureType == SignatureType.Validator) {
|
||||
// Pop last 20 bytes off of signature byte array.
|
||||
address validator = popAddress(signature);
|
||||
// Ensure signer has approved validator.
|
||||
if (!allowedValidators[signer][validator]) {
|
||||
return false;
|
||||
}
|
||||
isValid = IValidator(validator).isValidSignature(
|
||||
hash,
|
||||
signer,
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
|
||||
// Signer signed hash previously using the preSign function.
|
||||
} else if (signatureType == SignatureType.PreSigned) {
|
||||
isValid = preSigned[hash][signer];
|
||||
return isValid;
|
||||
|
||||
// Signature from Trezor hardware wallet.
|
||||
// It differs from web3.eth_sign in the encoding of message length
|
||||
// (Bitcoin varint encoding vs ascii-decimal, the latter is not
|
||||
// self-terminating which leads to ambiguities).
|
||||
// See also:
|
||||
// https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c#L602
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36
|
||||
} else if (signatureType == SignatureType.Trezor) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n\x41", hash),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Signer signed hash previously using the preSign function
|
||||
} else if (signatureType == SignatureType.PreSigned) {
|
||||
isValid = preSigned[hash][signer];
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Anything else is illegal (We do not return false because
|
||||
// the signature may actually be valid, just not in a format
|
||||
// that we currently support. In this case returning false
|
||||
// may lead the caller to incorrectly believe that the
|
||||
// signature was invalid.)
|
||||
revert(UNSUPPORTED_SIGNATURE_TYPE);
|
||||
}
|
||||
}
|
@@ -1,107 +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 "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
|
||||
contract MixinTransactions is
|
||||
LibExchangeErrors,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
|
||||
// Mapping of transaction hash => executed
|
||||
// This prevents transactions from being executed more than once.
|
||||
mapping (bytes32 => bool) public transactions;
|
||||
|
||||
// Address of current transaction signer
|
||||
address public currentContextAddress;
|
||||
|
||||
/// @dev Executes an exchange method call in the context of signer.
|
||||
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||
/// @param signer Address of transaction signer.
|
||||
/// @param data AbiV2 encoded calldata.
|
||||
/// @param signature Proof of signer transaction by signer.
|
||||
function executeTransaction(
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
{
|
||||
// Prevent reentrancy
|
||||
require(
|
||||
currentContextAddress == address(0),
|
||||
REENTRANCY_NOT_ALLOWED
|
||||
);
|
||||
|
||||
// Calculate transaction hash
|
||||
bytes32 transactionHash = keccak256(
|
||||
address(this),
|
||||
signer,
|
||||
salt,
|
||||
data
|
||||
);
|
||||
|
||||
// Validate transaction has not been executed
|
||||
require(
|
||||
!transactions[transactionHash],
|
||||
DUPLICATE_TRANSACTION_HASH
|
||||
);
|
||||
|
||||
// TODO: is SignatureType.Caller necessary if we make this check?
|
||||
if (signer != msg.sender) {
|
||||
// Validate signature
|
||||
require(
|
||||
isValidSignature(transactionHash, signer, signature),
|
||||
SIGNATURE_VALIDATION_FAILED
|
||||
);
|
||||
|
||||
// Set the current transaction signer
|
||||
currentContextAddress = signer;
|
||||
}
|
||||
|
||||
// Execute transaction
|
||||
transactions[transactionHash] = true;
|
||||
require(
|
||||
address(this).delegatecall(data),
|
||||
TRANSACTION_EXECUTION_FAILED
|
||||
);
|
||||
|
||||
// Reset current transaction signer
|
||||
// TODO: Check if gas is paid when currentContextAddress is already 0.
|
||||
currentContextAddress = address(0);
|
||||
}
|
||||
|
||||
/// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
|
||||
/// If calling a fill function, this address will represent the taker.
|
||||
/// If calling a cancel function, this address will represent the maker.
|
||||
/// @return Signer of 0x transaction if entry point is `executeTransaction`.
|
||||
/// `msg.sender` if entry point is any other function.
|
||||
function getCurrentContextAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
address contextAddress = currentContextAddress == address(0) ? msg.sender : currentContextAddress;
|
||||
return contextAddress;
|
||||
}
|
||||
}
|
@@ -1,515 +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 "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
|
||||
contract MixinWrapperFunctions is
|
||||
SafeMath,
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore
|
||||
{
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrder(
|
||||
Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
fillResults = fillOrder(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
require(
|
||||
fillResults.takerAssetFilledAmount == takerAssetFillAmount,
|
||||
COMPLETE_FILL_FAILED
|
||||
);
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrderNoThrow(
|
||||
Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// We need to call MExchangeCore.fillOrder using a delegatecall in
|
||||
// assembly so that we can intercept a call that throws. For this, we
|
||||
// need the input encoded in memory in the Ethereum ABIv2 format [1].
|
||||
|
||||
// | Area | Offset | Length | Contents |
|
||||
// | -------- |--------|---------|-------------------------------------------- |
|
||||
// | Header | 0x00 | 4 | function selector |
|
||||
// | Params | | 3 * 32 | function parameters: |
|
||||
// | | 0x00 | | 1. offset to order (*) |
|
||||
// | | 0x20 | | 2. takerAssetFillAmount |
|
||||
// | | 0x40 | | 3. offset to signature (*) |
|
||||
// | Data | | 12 * 32 | order: |
|
||||
// | | 0x000 | | 1. senderAddress |
|
||||
// | | 0x020 | | 2. makerAddress |
|
||||
// | | 0x040 | | 3. takerAddress |
|
||||
// | | 0x060 | | 4. feeRecipientAddress |
|
||||
// | | 0x080 | | 5. makerAssetAmount |
|
||||
// | | 0x0A0 | | 6. takerAssetAmount |
|
||||
// | | 0x0C0 | | 7. makerFeeAmount |
|
||||
// | | 0x0E0 | | 8. takerFeeAmount |
|
||||
// | | 0x100 | | 9. expirationTimeSeconds |
|
||||
// | | 0x120 | | 10. salt |
|
||||
// | | 0x140 | | 11. Offset to makerAssetProxyMetadata (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetProxyMetadata (*) |
|
||||
// | | 0x180 | 32 | makerAssetProxyMetadata Length |
|
||||
// | | 0x1A0 | ** | makerAssetProxyMetadata Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetProxyMetadata Length |
|
||||
// | | 0x1E0 | ** | takerAssetProxyMetadata Contents |
|
||||
// | | 0x200 | 32 | signature Length |
|
||||
// | | 0x220 | ** | signature Contents |
|
||||
|
||||
// * Offsets are calculated from the beginning of the current area: Header, Params, Data:
|
||||
// An offset stored in the Params area is calculated from the beginning of the Params section.
|
||||
// An offset stored in the Data area is calculated from the beginning of the Data section.
|
||||
|
||||
// ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
|
||||
|
||||
// [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
|
||||
|
||||
bytes4 fillOrderSelector = this.fillOrder.selector;
|
||||
|
||||
assembly {
|
||||
|
||||
// Areas below may use the following variables:
|
||||
// 1. <area>Start -- Start of this area in memory
|
||||
// 2. <area>End -- End of this area in memory. This value may
|
||||
// be precomputed (before writing contents),
|
||||
// or it may be computed as contents are written.
|
||||
// 3. <area>Offset -- Current offset into area. If an area's End
|
||||
// is precomputed, this variable tracks the
|
||||
// offsets of contents as they are written.
|
||||
|
||||
/////// Setup Header Area ///////
|
||||
// Load free memory pointer
|
||||
let headerAreaStart := mload(0x40)
|
||||
mstore(headerAreaStart, fillOrderSelector)
|
||||
let headerAreaEnd := add(headerAreaStart, 0x4)
|
||||
|
||||
/////// Setup Params Area ///////
|
||||
// This area is preallocated and written to later.
|
||||
// This is because we need to fill in offsets that have not yet been calculated.
|
||||
let paramsAreaStart := headerAreaEnd
|
||||
let paramsAreaEnd := add(paramsAreaStart, 0x60)
|
||||
let paramsAreaOffset := paramsAreaStart
|
||||
|
||||
/////// Setup Data Area ///////
|
||||
let dataAreaStart := paramsAreaEnd
|
||||
let dataAreaEnd := dataAreaStart
|
||||
|
||||
// Offset from the source data we're reading from
|
||||
let sourceOffset := order
|
||||
// arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
|
||||
let arrayLenBytes := 0
|
||||
let arrayLenWords := 0
|
||||
|
||||
/////// Write order Struct ///////
|
||||
// Write memory location of Order, relative to the start of the
|
||||
// parameter list, then increment the paramsAreaOffset respectively.
|
||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||
|
||||
// Write values for each field in the order
|
||||
// It would be nice to use a loop, but we save on gas by writing
|
||||
// the stores sequentially.
|
||||
mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
|
||||
mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
|
||||
mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
|
||||
mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
|
||||
mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
|
||||
mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
|
||||
mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
|
||||
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
|
||||
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
|
||||
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetProxyMetadata
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetProxyMetadata
|
||||
dataAreaEnd := add(dataAreaEnd, 0x180)
|
||||
sourceOffset := add(sourceOffset, 0x180)
|
||||
|
||||
// Write offset to <order.makerAssetProxyMetadata>
|
||||
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.makerAssetProxyMetadata>
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.makerAssetProxyMetadata>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.makerAssetProxyMetadata>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Write offset to <order.takerAssetProxyMetadata>
|
||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.takerAssetProxyMetadata>
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.takerAssetProxyMetadata>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.takerAssetProxyMetadata>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
/////// Write takerAssetFillAmount ///////
|
||||
mstore(paramsAreaOffset, takerAssetFillAmount)
|
||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||
|
||||
/////// Write signature ///////
|
||||
// Write offset to paramsArea
|
||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||
|
||||
// Calculate length of signature
|
||||
sourceOffset := signature
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of signature
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of signature
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Execute delegatecall
|
||||
let success := delegatecall(
|
||||
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
||||
address, // call address of this contract
|
||||
headerAreaStart, // pointer to start of input
|
||||
sub(dataAreaEnd, headerAreaStart), // length of input
|
||||
headerAreaStart, // write output over input
|
||||
128 // output size is 128 bytes
|
||||
)
|
||||
switch success
|
||||
case 0 {
|
||||
mstore(fillResults, 0)
|
||||
mstore(add(fillResults, 32), 0)
|
||||
mstore(add(fillResults, 64), 0)
|
||||
mstore(add(fillResults, 96), 0)
|
||||
}
|
||||
case 1 {
|
||||
mstore(fillResults, mload(headerAreaStart))
|
||||
mstore(add(fillResults, 32), mload(add(headerAreaStart, 32)))
|
||||
mstore(add(fillResults, 64), mload(add(headerAreaStart, 64)))
|
||||
mstore(add(fillResults, 96), mload(add(headerAreaStart, 96)))
|
||||
}
|
||||
}
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
function batchFillOrders(
|
||||
Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
fillOrder(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrKill.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
function batchFillOrKillOrders(
|
||||
Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
fillOrKillOrder(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
function batchFillOrdersNoThrow(
|
||||
Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
fillOrderNoThrow(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrders(
|
||||
Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being sold by taker must be the same for each order
|
||||
// TODO: optimize by only using takerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of takerAsset has been sold
|
||||
if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrdersNoThrow(
|
||||
Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being sold by taker must be the same for each order
|
||||
// TODO: optimize by only using takerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of takerAsset has been sold
|
||||
if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrders(
|
||||
Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being bought by taker must be the same for each order
|
||||
// TODO: optimize by only using makerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of makerAsset has been bought
|
||||
if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrdersNoThrow(
|
||||
Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being bought by taker must be the same for each order
|
||||
// TODO: optimize by only using makerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of makerAsset has been bought
|
||||
if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orders Array of order specifications.
|
||||
function batchCancelOrders(Order[] memory orders)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
cancelOrder(orders[i]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,41 +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;
|
||||
|
||||
contract IAssetProxyDispatcher {
|
||||
|
||||
/// @dev Registers an asset proxy to an asset proxy id.
|
||||
/// An id can only be assigned to a single proxy at a given time.
|
||||
/// @param assetProxyId Id to register`newAssetProxy` under.
|
||||
/// @param newAssetProxy Address of new asset proxy to register, or 0x0 to unset assetProxyId.
|
||||
/// @param oldAssetProxy Existing asset proxy to overwrite, or 0x0 if assetProxyId is currently unused.
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy)
|
||||
external;
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
|
||||
function getAssetProxy(uint8 assetProxyId)
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
}
|
@@ -1,36 +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 "./IExchangeCore.sol";
|
||||
import "./IMatchOrders.sol";
|
||||
import "./ISignatureValidator.sol";
|
||||
import "./ITransactions.sol";
|
||||
import "./IAssetProxyDispatcher.sol";
|
||||
import "./IWrapperFunctions.sol";
|
||||
|
||||
contract IExchange is
|
||||
IExchangeCore,
|
||||
IMatchOrders,
|
||||
ISignatureValidator,
|
||||
ITransactions,
|
||||
IAssetProxyDispatcher,
|
||||
IWrapperFunctions
|
||||
{}
|
@@ -1,80 +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 "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IExchangeCore {
|
||||
|
||||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
|
||||
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 salt)
|
||||
external;
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev After calling, the order can not be filled anymore.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @return True if the order state changed to cancelled.
|
||||
/// False if the transaction was already cancelled or expired.
|
||||
function cancelOrder(LibOrder.Order memory order)
|
||||
public
|
||||
returns (bool);
|
||||
|
||||
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||
/// @param order Order to gather information on.
|
||||
/// @return OrderInfo Information about the order and its state.
|
||||
/// See LibOrder.OrderInfo for a complete description.
|
||||
function getOrderInfo(LibOrder.Order memory order)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo memory orderInfo);
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param orderStatus Status of order to be filled.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
LibOrder.Order memory order,
|
||||
uint8 orderStatus,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
uint256 takerAssetFillAmount
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
uint8 status,
|
||||
LibFillResults.FillResults memory fillResults
|
||||
);
|
||||
}
|
@@ -1,44 +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 "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IMatchOrders {
|
||||
|
||||
/// @dev Match two complementary orders that have a profitable spread.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the left order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftSignature Proof that order was created by the left maker.
|
||||
/// @param rightSignature Proof that order was created by the right maker.
|
||||
/// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
|
||||
/// TODO: Make this function external once supported by Solidity (See Solidity Issues #3199, #1603)
|
||||
function matchOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
}
|
@@ -1,42 +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;
|
||||
|
||||
contract ISignatureValidator {
|
||||
|
||||
/// @dev Approves a hash on-chain using any valid signature type.
|
||||
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
function preSign(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
|
||||
/// @param validator Address of Validator contract.
|
||||
/// @param approval Approval or disapproval of Validator contract.
|
||||
function setSignatureValidatorApproval(
|
||||
address validator,
|
||||
bool approval
|
||||
)
|
||||
external;
|
||||
}
|
@@ -1,33 +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;
|
||||
|
||||
contract ITransactions {
|
||||
|
||||
/// @dev Executes an exchange method call in the context of signer.
|
||||
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||
/// @param signer Address of transaction signer.
|
||||
/// @param data AbiV2 encoded calldata.
|
||||
/// @param signature Proof of signer transaction by signer.
|
||||
function executeTransaction(
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature)
|
||||
external;
|
||||
}
|
@@ -1,36 +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.23;
|
||||
|
||||
contract IValidator {
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
@@ -1,34 +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;
|
||||
|
||||
contract IWallet {
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
@@ -1,138 +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 "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IWrapperFunctions is
|
||||
LibOrder,
|
||||
LibFillResults
|
||||
{
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order LibOrder.Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order LibOrder.Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public;
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrKill.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public;
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public;
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orders Array of order specifications.
|
||||
function batchCancelOrders(LibOrder.Order[] memory orders)
|
||||
public;
|
||||
}
|
@@ -1,61 +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;
|
||||
|
||||
contract LibExchangeErrors {
|
||||
|
||||
// Core revert reasons
|
||||
string constant GT_ZERO_AMOUNT_REQUIRED = "Amount must be greater than 0.";
|
||||
string constant SIGNATURE_VALIDATION_FAILED = "Signature validation failed.";
|
||||
string constant INVALID_SENDER = "Invalid `msg.sender`.";
|
||||
string constant INVALID_CONTEXT = "Function called in an invalid context.";
|
||||
string constant INVALID_NEW_MAKER_EPOCH = "Specified salt must be greater than or equal to existing makerEpoch.";
|
||||
|
||||
// Order revert reasons
|
||||
string constant INVALID_ORDER_TAKER_ASSET_AMOUNT = "Invalid order taker asset amount: expected a non-zero value.";
|
||||
string constant INVALID_ORDER_MAKER_ASSET_AMOUNT = "Invalid order maker asset amount: expected a non-zero value.";
|
||||
|
||||
// Transaction revert reasons
|
||||
string constant REENTRANCY_NOT_ALLOWED = "`executeTransaction` is not allowed to call itself recursively.";
|
||||
string constant DUPLICATE_TRANSACTION_HASH = "Transaction has already been executed.";
|
||||
string constant TRANSACTION_EXECUTION_FAILED = "Transaction execution failed.";
|
||||
|
||||
// Wrapper revert reasons
|
||||
string constant COMPLETE_FILL_FAILED = "Desired fill amount could not be completely filled.";
|
||||
string constant ASSET_DATA_MISMATCH = "Asset data must be the same for each order.";
|
||||
|
||||
// Asset proxy dispatcher revert reasons
|
||||
string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
|
||||
string constant OLD_ASSET_PROXY_MISMATCH = "Old asset proxy does not match asset proxy at given id.";
|
||||
string constant NEW_ASSET_PROXY_MISMATCH = "New asset proxy id does not match given id.";
|
||||
|
||||
// Signature validator revert reasons
|
||||
string constant INVALID_SIGNATURE_LENGTH = "Invalid signature length.";
|
||||
string constant ILLEGAL_SIGNATURE_TYPE = "Illegal signature type.";
|
||||
string constant UNSUPPORTED_SIGNATURE_TYPE = "Unsupported signature type.";
|
||||
|
||||
// Order matching revert reasons
|
||||
string constant ASSET_MISMATCH_MAKER_TAKER = "Left order maker asset is different from right order taker asset.";
|
||||
string constant ASSET_MISMATCH_TAKER_MAKER = "Left order taker asset is different from right order maker asset.";
|
||||
string constant NEGATIVE_SPREAD = "Matched orders must have a positive spread.";
|
||||
string constant MISCALCULATED_TRANSFER_AMOUNTS = "A miscalculation occurred: the left maker would receive more than the right maker would spend.";
|
||||
string constant ROUNDING_ERROR_TRANSFER_AMOUNTS = "A rounding error occurred when calculating transfer amounts for matched orders.";
|
||||
string constant FAILED_TO_CALCULATE_FILL_RESULTS_FOR_LEFT_ORDER = "Failed to calculate fill results for left order.";
|
||||
string constant FAILED_TO_CALCULATE_FILL_RESULTS_FOR_RIGHT_ORDER = "Failed to calculate fill results for right order.";
|
||||
}
|
@@ -1,68 +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 "../../../utils/SafeMath/SafeMath.sol";
|
||||
|
||||
contract LibFillResults is
|
||||
SafeMath
|
||||
{
|
||||
|
||||
struct FillResults {
|
||||
uint256 makerAssetFilledAmount;
|
||||
uint256 takerAssetFilledAmount;
|
||||
uint256 makerFeePaid;
|
||||
uint256 takerFeePaid;
|
||||
}
|
||||
|
||||
struct MatchedFillResults {
|
||||
LibFillResults.FillResults left;
|
||||
LibFillResults.FillResults right;
|
||||
uint256 takerFillAmount;
|
||||
}
|
||||
|
||||
/// @dev Adds properties of both FillResults instances.
|
||||
/// Modifies the first FillResults instance specified.
|
||||
/// @param totalFillResults Fill results instance that will be added onto.
|
||||
/// @param singleFillResults Fill results instance that will be added to totalFillResults.
|
||||
function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
totalFillResults.makerAssetFilledAmount = safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
|
||||
totalFillResults.takerAssetFilledAmount = safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
|
||||
totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid);
|
||||
totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid);
|
||||
}
|
||||
|
||||
/// @dev Returns a null fill results struct
|
||||
function getNullFillResults()
|
||||
internal
|
||||
pure
|
||||
returns (FillResults memory)
|
||||
{
|
||||
// returns zeroed out FillResults instance
|
||||
return FillResults({
|
||||
makerAssetFilledAmount: 0,
|
||||
takerAssetFilledAmount: 0,
|
||||
makerFeePaid: 0,
|
||||
takerFeePaid: 0
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,93 +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 "../../../utils/SafeMath/SafeMath.sol";
|
||||
|
||||
contract LibMath is
|
||||
SafeMath
|
||||
{
|
||||
string constant ROUNDING_ERROR_ON_PARTIAL_AMOUNT = "A rounding error occurred when calculating partial transfer amounts.";
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmount(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
partialAmount = safeDiv(
|
||||
safeMul(numerator, target),
|
||||
denominator
|
||||
);
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// Throws if there is a rounding error.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function safeGetPartialAmount(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
internal pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
require(
|
||||
!isRoundingError(numerator, denominator, target),
|
||||
ROUNDING_ERROR_ON_PARTIAL_AMOUNT
|
||||
);
|
||||
return getPartialAmount(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingError(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
internal
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
uint256 remainder = mulmod(target, numerator, denominator);
|
||||
if (remainder == 0) {
|
||||
return false; // No rounding error.
|
||||
}
|
||||
|
||||
uint256 errPercentageTimes1000000 = safeDiv(
|
||||
safeMul(remainder, 1000000),
|
||||
safeMul(numerator, target)
|
||||
);
|
||||
isError = errPercentageTimes1000000 > 1000;
|
||||
return isError;
|
||||
}
|
||||
}
|
@@ -1,99 +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;
|
||||
|
||||
contract LibOrder {
|
||||
|
||||
bytes32 constant DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(
|
||||
"DomainSeparator(address contract)"
|
||||
);
|
||||
|
||||
bytes32 constant ORDER_SCHEMA_HASH = keccak256(
|
||||
"Order(",
|
||||
"address makerAddress,",
|
||||
"address takerAddress,",
|
||||
"address feeRecipientAddress,",
|
||||
"address senderAddress,",
|
||||
"uint256 makerAssetAmount,",
|
||||
"uint256 takerAssetAmount,",
|
||||
"uint256 makerFee,",
|
||||
"uint256 takerFee,",
|
||||
"uint256 expirationTimeSeconds,",
|
||||
"uint256 salt,",
|
||||
"bytes makerAssetData,",
|
||||
"bytes takerAssetData,",
|
||||
")"
|
||||
);
|
||||
|
||||
struct Order {
|
||||
address makerAddress;
|
||||
address takerAddress;
|
||||
address feeRecipientAddress;
|
||||
address senderAddress;
|
||||
uint256 makerAssetAmount;
|
||||
uint256 takerAssetAmount;
|
||||
uint256 makerFee;
|
||||
uint256 takerFee;
|
||||
uint256 expirationTimeSeconds;
|
||||
uint256 salt;
|
||||
bytes makerAssetData;
|
||||
bytes takerAssetData;
|
||||
}
|
||||
|
||||
struct OrderInfo {
|
||||
// See LibStatus for a complete description of order statuses
|
||||
uint8 orderStatus;
|
||||
// Keccak-256 EIP712 hash of the order
|
||||
bytes32 orderHash;
|
||||
// Amount of order that has been filled
|
||||
uint256 orderTakerAssetFilledAmount;
|
||||
}
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of the order.
|
||||
/// @param order The order structure.
|
||||
/// @return Keccak-256 EIP712 hash of the order.
|
||||
function getOrderHash(Order memory order)
|
||||
internal
|
||||
view
|
||||
returns (bytes32 orderHash)
|
||||
{
|
||||
// TODO: EIP712 is not finalized yet
|
||||
// Source: https://github.com/ethereum/EIPs/pull/712
|
||||
orderHash = keccak256(
|
||||
DOMAIN_SEPARATOR_SCHEMA_HASH,
|
||||
keccak256(address(this)),
|
||||
ORDER_SCHEMA_HASH,
|
||||
keccak256(
|
||||
order.makerAddress,
|
||||
order.takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
order.senderAddress,
|
||||
order.makerAssetAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerFee,
|
||||
order.takerFee,
|
||||
order.expirationTimeSeconds,
|
||||
order.salt,
|
||||
keccak256(order.makerAssetData),
|
||||
keccak256(order.takerAssetData)
|
||||
)
|
||||
);
|
||||
return orderHash;
|
||||
}
|
||||
}
|
@@ -1,51 +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;
|
||||
|
||||
contract LibStatus {
|
||||
|
||||
// Exchange Status Codes
|
||||
enum Status {
|
||||
/// Default Status ///
|
||||
INVALID, // General invalid status
|
||||
|
||||
/// General Exchange Statuses ///
|
||||
SUCCESS, // Indicates a successful operation
|
||||
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
|
||||
INSUFFICIENT_BALANCE_OR_ALLOWANCE, // Insufficient balance or allowance for token transfer
|
||||
TAKER_ASSET_FILL_AMOUNT_TOO_LOW, // takerAssetFillAmount is <= 0
|
||||
INVALID_SIGNATURE, // Invalid signature
|
||||
INVALID_SENDER, // Invalid sender
|
||||
INVALID_TAKER, // Invalid taker
|
||||
INVALID_MAKER, // Invalid maker
|
||||
|
||||
/// Order State Statuses ///
|
||||
// A valid order remains fillable until it is expired, fully filled, or cancelled.
|
||||
// An order's state is unaffected by external factors, like account balances.
|
||||
ORDER_INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
|
||||
ORDER_INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
|
||||
ORDER_FILLABLE, // Order is fillable
|
||||
ORDER_EXPIRED, // Order has already expired
|
||||
ORDER_FULLY_FILLED, // Order is fully filled
|
||||
ORDER_CANCELLED // Order has been cancelled
|
||||
}
|
||||
|
||||
event ExchangeStatus(uint8 indexed statusId, bytes32 indexed orderHash);
|
||||
}
|
@@ -1,47 +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 "../interfaces/IAssetProxyDispatcher.sol";
|
||||
|
||||
contract MAssetProxyDispatcher is
|
||||
IAssetProxyDispatcher
|
||||
{
|
||||
|
||||
// Logs registration of new asset proxy
|
||||
event AssetProxySet(
|
||||
uint8 id,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy
|
||||
);
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -1,117 +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 "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
import "../interfaces/IExchangeCore.sol";
|
||||
|
||||
contract MExchangeCore is
|
||||
IExchangeCore
|
||||
{
|
||||
|
||||
// Fill event is emitted whenever an order is filled.
|
||||
event Fill(
|
||||
address indexed makerAddress,
|
||||
address takerAddress,
|
||||
address indexed feeRecipientAddress,
|
||||
uint256 makerAssetFilledAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 makerFeePaid,
|
||||
uint256 takerFeePaid,
|
||||
bytes32 indexed orderHash,
|
||||
bytes makerAssetData,
|
||||
bytes takerAssetData
|
||||
);
|
||||
|
||||
// Cancel event is emitted whenever an individual order is cancelled.
|
||||
event Cancel(
|
||||
address indexed makerAddress,
|
||||
address indexed feeRecipientAddress,
|
||||
bytes32 indexed orderHash,
|
||||
bytes makerAssetData,
|
||||
bytes takerAssetData
|
||||
);
|
||||
|
||||
// CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully.
|
||||
event CancelUpTo(
|
||||
address indexed makerAddress,
|
||||
uint256 makerEpoch
|
||||
);
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderStatus Status of order to be filled.
|
||||
/// @param orderHash Hash of order to be filled.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
LibOrder.Order memory order,
|
||||
uint8 orderStatus,
|
||||
bytes32 orderHash,
|
||||
address takerAddress,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function updateFilledState(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
bytes32 orderHash,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
LibFillResults.FillResults memory fillResults
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order that was cancelled.
|
||||
/// @param orderStatus Status of order that was cancelled.
|
||||
/// @param orderHash Hash of order that was cancelled.
|
||||
function assertValidCancel(
|
||||
LibOrder.Order memory order,
|
||||
uint8 orderStatus,
|
||||
bytes32 orderHash
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Updates state with results of cancelling an order.
|
||||
/// State is only updated if the order is currently fillable.
|
||||
/// Otherwise, updating state would have no effect.
|
||||
/// @param order that was cancelled.
|
||||
/// @param orderStatus Status of order that was cancelled.
|
||||
/// @param orderHash Hash of order that was cancelled.
|
||||
/// @return stateUpdated Returns true only if state was updated.
|
||||
function updateCancelledState(
|
||||
LibOrder.Order memory order,
|
||||
uint8 orderStatus,
|
||||
bytes32 orderHash
|
||||
)
|
||||
internal
|
||||
returns (bool stateUpdated);
|
||||
}
|
@@ -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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
import "./MExchangeCore.sol";
|
||||
import "../interfaces/IMatchOrders.sol";
|
||||
|
||||
contract MMatchOrders is
|
||||
IMatchOrders
|
||||
{
|
||||
|
||||
/// @dev Validates context for matchOrders. Succeeds or throws.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function assertValidMatch(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Validates matched fill results. Succeeds or throws.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function assertValidMatchResults(LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
internal;
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the leftOrder order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftOrderStatus Order status of left order.
|
||||
/// @param rightOrderStatus Order status of right order.
|
||||
/// @param leftOrderFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderFilledAmount Amount of right order already filled.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function calculateMatchedFillResults(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint8 leftOrderStatus,
|
||||
uint8 rightOrderStatus,
|
||||
uint256 leftOrderFilledAmount,
|
||||
uint256 rightOrderFilledAmount
|
||||
)
|
||||
internal
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
}
|
@@ -1,50 +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 "../libs/LibOrder.sol";
|
||||
import "./MMatchOrders.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract MSettlement {
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAddress Address selling takerAsset and buying makerAsset.
|
||||
/// @param fillResults Amounts to be filled and fees paid by maker and taker.
|
||||
function settleOrder(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
LibFillResults.FillResults memory fillResults
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
|
||||
/// @param leftOrder First matched order.
|
||||
/// @param rightOrder Second matched order.
|
||||
/// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
|
||||
/// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
|
||||
function settleMatchedOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
address takerAddress,
|
||||
LibFillResults.MatchedFillResults memory matchedFillResults
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -1,52 +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 "../interfaces/ISignatureValidator.sol";
|
||||
|
||||
contract MSignatureValidator is
|
||||
ISignatureValidator
|
||||
{
|
||||
// Allowed signature types.
|
||||
enum SignatureType {
|
||||
Illegal, // 0x00, default value
|
||||
Invalid, // 0x01
|
||||
EIP712, // 0x02
|
||||
EthSign, // 0x03
|
||||
Caller, // 0x04
|
||||
Wallet, // 0x05
|
||||
Validator, // 0x06
|
||||
PreSigned, // 0x07
|
||||
Trezor // 0x08
|
||||
}
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signer Address of signer.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
@@ -1,35 +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 "../interfaces/ITransactions.sol";
|
||||
|
||||
contract MTransactions is
|
||||
ITransactions
|
||||
{
|
||||
|
||||
/// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
|
||||
/// If calling a fill function, this address will represent the taker.
|
||||
/// If calling a cancel function, this address will represent the maker.
|
||||
/// @return Signer of 0x transaction if entry point is `executeTransaction`.
|
||||
/// `msg.sender` if entry point is any other function.
|
||||
function getCurrentContextAddress()
|
||||
internal
|
||||
view
|
||||
returns (address);
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import { Ownable_v1 as Ownable } from "../Ownable/Ownable_v1.sol";
|
||||
import { Ownable_v1 as Ownable } from "../../../previous/Ownable/Ownable_v1.sol";
|
||||
|
||||
/// @title Token Registry - Stores metadata associated with ERC20 tokens. See ERC22 https://github.com/ethereum/EIPs/issues/22
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import { Token_v1 as Token } from "../Token/Token_v1.sol";
|
||||
import { Ownable_v1 as Ownable } from "../Ownable/Ownable_v1.sol";
|
||||
import { Token_v1 as Token } from "../../../previous/Token/Token_v1.sol";
|
||||
import { Ownable_v1 as Ownable } from "../../../previous/Ownable/Ownable_v1.sol";
|
||||
|
||||
/// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
||||
contract TokenTransferProxy_v1 is Ownable {
|
||||
contract TokenTransferProxy is Ownable {
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized {
|
@@ -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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../Mintable/Mintable.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
|
||||
contract DummyERC20Token is Mintable, Ownable {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint256 public decimals;
|
||||
|
||||
constructor (
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint256 _decimals,
|
||||
uint256 _totalSupply)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
totalSupply = _totalSupply;
|
||||
balances[msg.sender] = _totalSupply;
|
||||
}
|
||||
|
||||
function setBalance(address _target, uint256 _value)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
uint256 currBalance = balanceOf(_target);
|
||||
if (_value < currBalance) {
|
||||
totalSupply = safeSub(totalSupply, safeSub(currBalance, _value));
|
||||
} else {
|
||||
totalSupply = safeAdd(totalSupply, safeSub(_value, currBalance));
|
||||
}
|
||||
balances[_target] = _value;
|
||||
}
|
||||
}
|
@@ -1,58 +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 "../../tokens/ERC721Token/ERC721Token.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
|
||||
contract DummyERC721Token is
|
||||
Ownable,
|
||||
ERC721Token
|
||||
{
|
||||
|
||||
/**
|
||||
* @dev Constructor passes its arguments to the base ERC721Token constructor
|
||||
* @param name of token
|
||||
* @param symbol of token
|
||||
*/
|
||||
constructor (
|
||||
string name,
|
||||
string symbol)
|
||||
public
|
||||
ERC721Token(name, symbol)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @dev Function to mint a new token
|
||||
* @dev Reverts if the given token ID already exists
|
||||
* @param to address the beneficiary that will own the minted token
|
||||
* @param tokenId uint256 ID of the token to be minted by the msg.sender
|
||||
*/
|
||||
function mint(address to, uint256 tokenId)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
!exists(tokenId),
|
||||
"Token with tokenId already exists."
|
||||
);
|
||||
_mint(to, tokenId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import { Mintable } from "../Mintable/Mintable.sol";
|
||||
import { Ownable } from "../../utils/Ownable/Ownable.sol";
|
||||
|
||||
contract DummyToken is Mintable, Ownable {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint public decimals;
|
||||
|
||||
function DummyToken(
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint _decimals,
|
||||
uint _totalSupply)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
totalSupply = _totalSupply;
|
||||
balances[msg.sender] = _totalSupply;
|
||||
}
|
||||
|
||||
function setBalance(address _target, uint _value)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
uint currBalance = balanceOf(_target);
|
||||
if (_value < currBalance) {
|
||||
totalSupply = safeSub(totalSupply, safeSub(currBalance, _value));
|
||||
} else {
|
||||
totalSupply = safeAdd(totalSupply, safeSub(_value, currBalance));
|
||||
}
|
||||
balances[_target] = _value;
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import { ERC20Token } from "../../tokens/ERC20Token/ERC20Token.sol";
|
||||
|
||||
contract MaliciousToken is ERC20Token {
|
||||
uint8 stateToUpdate = 1; // Not null so that change only requires 5000 gas
|
||||
|
||||
function updateState()
|
||||
internal
|
||||
{
|
||||
stateToUpdate++;
|
||||
}
|
||||
|
||||
function balanceOf(address _owner)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
updateState();
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
function allowance(address _owner, address _spender)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
updateState();
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
}
|
@@ -1,39 +1,17 @@
|
||||
/*
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
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 "../../tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol";
|
||||
import "../../utils/SafeMath/SafeMath.sol";
|
||||
import { UnlimitedAllowanceToken } from "../../tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol";
|
||||
import { SafeMath } from "../../utils/SafeMath/SafeMath.sol";
|
||||
|
||||
/*
|
||||
* Mintable
|
||||
* Base contract that creates a mintable UnlimitedAllowanceToken
|
||||
*/
|
||||
contract Mintable is UnlimitedAllowanceToken, SafeMath {
|
||||
function mint(uint256 _value)
|
||||
function mint(uint _value)
|
||||
public
|
||||
{
|
||||
require(
|
||||
_value <= 100000000000000000000,
|
||||
"Minting more than 100000000000000000000 is not allowed."
|
||||
);
|
||||
require(_value <= 100000000000000000000);
|
||||
balances[msg.sender] = safeAdd(_value, balances[msg.sender]);
|
||||
totalSupply = safeAdd(totalSupply, _value);
|
||||
}
|
||||
|
@@ -1,34 +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 "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
|
||||
|
||||
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
|
||||
function publicDispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
{
|
||||
dispatchTransferFrom(assetMetadata, from, to, amount);
|
||||
}
|
||||
}
|
@@ -1,169 +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 "../../utils/LibBytes/LibBytes.sol";
|
||||
|
||||
contract TestLibBytes is
|
||||
LibBytes
|
||||
{
|
||||
|
||||
/// @dev Pops the last byte off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
/// @return The byte that was popped off.
|
||||
function publicPopByte(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory, bytes1 result)
|
||||
{
|
||||
result = popByte(b);
|
||||
return (b, result);
|
||||
}
|
||||
|
||||
/// @dev Pops the last 20 bytes off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
/// @return The 20 byte address that was popped off.
|
||||
function publicPopAddress(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory, address result)
|
||||
{
|
||||
result = popAddress(b);
|
||||
return (b, result);
|
||||
}
|
||||
|
||||
/// @dev Tests equality of two byte arrays.
|
||||
/// @param lhs First byte array to compare.
|
||||
/// @param rhs Second byte array to compare.
|
||||
/// @return True if arrays are the same. False otherwise.
|
||||
function publicAreBytesEqual(bytes memory lhs, bytes memory rhs)
|
||||
public
|
||||
pure
|
||||
returns (bool equal)
|
||||
{
|
||||
equal = areBytesEqual(lhs, rhs);
|
||||
return equal;
|
||||
}
|
||||
|
||||
/// @dev Reads an address from a position in a byte array.
|
||||
/// @param b Byte array containing an address.
|
||||
/// @param index Index in byte array of address.
|
||||
/// @return address from byte array.
|
||||
function publicReadAddress(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
public
|
||||
pure
|
||||
returns (address result)
|
||||
{
|
||||
result = readAddress(b, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Writes an address into a specific position in a byte array.
|
||||
/// @param b Byte array to insert address into.
|
||||
/// @param index Index in byte array of address.
|
||||
/// @param input Address to put into byte array.
|
||||
function publicWriteAddress(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
address input)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
writeAddress(b, index, input);
|
||||
return b;
|
||||
}
|
||||
|
||||
/// @dev Reads a bytes32 value from a position in a byte array.
|
||||
/// @param b Byte array containing a bytes32 value.
|
||||
/// @param index Index in byte array of bytes32 value.
|
||||
/// @return bytes32 value from byte array.
|
||||
function publicReadBytes32(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
public
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
{
|
||||
result = readBytes32(b, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Writes a bytes32 into a specific position in a byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
/// @param input bytes32 to put into byte array.
|
||||
function publicWriteBytes32(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes32 input)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
writeBytes32(b, index, input);
|
||||
return b;
|
||||
}
|
||||
|
||||
/// @dev Reads a uint256 value from a position in a byte array.
|
||||
/// @param b Byte array containing a uint256 value.
|
||||
/// @param index Index in byte array of uint256 value.
|
||||
/// @return uint256 value from byte array.
|
||||
function publicReadUint256(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
public
|
||||
pure
|
||||
returns (uint256 result)
|
||||
{
|
||||
result = readUint256(b, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Writes a uint256 into a specific position in a byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
/// @param input uint256 to put into byte array.
|
||||
function publicWriteUint256(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
uint256 input)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
writeUint256(b, index, input);
|
||||
return b;
|
||||
}
|
||||
|
||||
/// @dev Reads the first 4 bytes from a byte array of arbitrary length.
|
||||
/// @param b Byte array to read first 4 bytes from.
|
||||
/// @return First 4 bytes of data.
|
||||
function publicReadFirst4(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes4 result)
|
||||
{
|
||||
result = readFirst4(b);
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -1,96 +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 "../../protocol/Exchange/libs/LibMath.sol";
|
||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
||||
import "../../protocol/Exchange/libs/LibFillResults.sol";
|
||||
|
||||
contract TestLibs is
|
||||
LibMath,
|
||||
LibOrder,
|
||||
LibFillResults
|
||||
{
|
||||
function publicGetPartialAmount(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
partialAmount = getPartialAmount(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
);
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
function publicIsRoundingError(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
isError = isRoundingError(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
);
|
||||
return isError;
|
||||
}
|
||||
|
||||
function publicGetOrderHash(Order memory order)
|
||||
public
|
||||
view
|
||||
returns (bytes32 orderHash)
|
||||
{
|
||||
orderHash = getOrderHash(order);
|
||||
return orderHash;
|
||||
}
|
||||
|
||||
function getOrderSchemaHash()
|
||||
public
|
||||
view
|
||||
returns (bytes32)
|
||||
{
|
||||
return ORDER_SCHEMA_HASH;
|
||||
}
|
||||
|
||||
function getDomainSeparatorSchemaHash()
|
||||
public
|
||||
view
|
||||
returns (bytes32)
|
||||
{
|
||||
return DOMAIN_SEPARATOR_SCHEMA_HASH;
|
||||
}
|
||||
|
||||
function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
|
||||
public
|
||||
pure
|
||||
returns (FillResults memory)
|
||||
{
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
return totalFillResults;
|
||||
}
|
||||
}
|
@@ -1,46 +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 "../../protocol/Exchange/MixinSignatureValidator.sol";
|
||||
import "../../protocol/Exchange/MixinTransactions.sol";
|
||||
|
||||
contract TestSignatureValidator is
|
||||
MixinSignatureValidator,
|
||||
MixinTransactions
|
||||
{
|
||||
|
||||
function publicIsValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
isValid = isValidSignature(
|
||||
hash,
|
||||
signer,
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
}
|
||||
}
|
@@ -1,133 +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.23;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../protocol/Exchange/interfaces/IExchange.sol";
|
||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
|
||||
contract Whitelist is
|
||||
Ownable
|
||||
{
|
||||
// Revert reasons
|
||||
string constant MAKER_NOT_WHITELISTED = "Maker address not whitelisted.";
|
||||
string constant TAKER_NOT_WHITELISTED = "Taker address not whitelisted.";
|
||||
string constant INVALID_SENDER = "Sender must equal transaction origin.";
|
||||
|
||||
// Mapping of address => whitelist status.
|
||||
mapping (address => bool) public isWhitelisted;
|
||||
|
||||
// Exchange contract.
|
||||
IExchange EXCHANGE;
|
||||
|
||||
byte constant VALIDATOR_SIGNATURE_BYTE = "\x06";
|
||||
bytes TX_ORIGIN_SIGNATURE;
|
||||
|
||||
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 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(
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
/// @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 signer Address that should have signed the given hash.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
return signer == tx.origin;
|
||||
}
|
||||
}
|
@@ -1,90 +1,45 @@
|
||||
/*
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
import { Token } from "../Token/Token.sol";
|
||||
|
||||
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
|
||||
contract ERC20Token is Token {
|
||||
|
||||
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 "./IERC20Token.sol";
|
||||
|
||||
contract ERC20Token is IERC20Token {
|
||||
|
||||
string constant INSUFFICIENT_BALANCE = "Insufficient balance to complete transfer.";
|
||||
string constant INSUFFICIENT_ALLOWANCE = "Insufficient allowance to complete transfer.";
|
||||
string constant OVERFLOW = "Transfer would result in an overflow.";
|
||||
|
||||
mapping (address => uint256) balances;
|
||||
mapping (address => mapping (address => uint256)) allowed;
|
||||
|
||||
uint256 public totalSupply;
|
||||
|
||||
function transfer(address _to, uint256 _value)
|
||||
function transfer(address _to, uint _value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
require(
|
||||
balances[msg.sender] >= _value,
|
||||
INSUFFICIENT_BALANCE
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
OVERFLOW
|
||||
);
|
||||
require(balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]);
|
||||
balances[msg.sender] -= _value;
|
||||
balances[_to] += _value;
|
||||
emit Transfer(msg.sender, _to, _value);
|
||||
Transfer(msg.sender, _to, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint256 _value)
|
||||
function transferFrom(address _from, address _to, uint _value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
require(
|
||||
balances[_from] >= _value,
|
||||
INSUFFICIENT_BALANCE
|
||||
);
|
||||
require(
|
||||
allowed[_from][msg.sender] >= _value,
|
||||
INSUFFICIENT_ALLOWANCE
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
OVERFLOW
|
||||
);
|
||||
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]);
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
emit Transfer(_from, _to, _value);
|
||||
Transfer(_from, _to, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address _spender, uint256 _value)
|
||||
function approve(address _spender, uint _value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
allowed[msg.sender][_spender] = _value;
|
||||
emit Approval(msg.sender, _spender, _value);
|
||||
Approval(msg.sender, _spender, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function balanceOf(address _owner)
|
||||
public view
|
||||
returns (uint256)
|
||||
public
|
||||
view
|
||||
returns (uint)
|
||||
{
|
||||
return balances[_owner];
|
||||
}
|
||||
@@ -92,9 +47,12 @@ contract ERC20Token is IERC20Token {
|
||||
function allowance(address _owner, address _spender)
|
||||
public
|
||||
view
|
||||
returns (uint256)
|
||||
returns (uint)
|
||||
{
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
}
|
||||
|
||||
mapping (address => uint) balances;
|
||||
mapping (address => mapping (address => uint)) allowed;
|
||||
uint public totalSupply;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user