Compare commits
484 Commits
@0xproject
...
@0xproject
Author | SHA1 | Date | |
---|---|---|---|
|
0bfcf79e79 | ||
|
49f5495c45 | ||
|
9e431df848 | ||
|
12476c52a4 | ||
|
8fd9aebcb9 | ||
|
8c83f4ba3b | ||
|
25b6d1a232 | ||
|
880cbd88c2 | ||
|
dcd53c3c5b | ||
|
3e64b3da39 | ||
|
9a748c8bf1 | ||
|
53eae14763 | ||
|
074c42e8b6 | ||
|
8633fa7024 | ||
|
19668b9b48 | ||
|
3f02631b98 | ||
|
da46eefe2e | ||
|
a3ca3ed33f | ||
|
efaa33c4d5 | ||
|
0cdfe7f458 | ||
|
2ad411ea29 | ||
|
55cbcd728d | ||
|
8880860105 | ||
|
0c238448fd | ||
|
8a76fdc126 | ||
|
433f830cf3 | ||
|
8893bc102c | ||
|
0cf9927132 | ||
|
5993125cc7 | ||
|
0c34309133 | ||
|
3d6ce0fb76 | ||
|
54f79c2798 | ||
|
d0a3779091 | ||
|
ff0960b174 | ||
|
7032825e35 | ||
|
d118533d87 | ||
|
35f4f75733 | ||
|
ef61c3543f | ||
|
897560745a | ||
|
5a8539a122 | ||
|
d9292a70bf | ||
|
a9c23b7c28 | ||
|
263bfb1bda | ||
|
e7eb220c50 | ||
|
7d67005820 | ||
|
fadd91b6a2 | ||
|
5fa6a2848f | ||
|
7ab921669b | ||
|
4811dfa663 | ||
|
2c7d6a7711 | ||
|
0e354e5ea1 | ||
|
d172a97247 | ||
|
8a3df7e434 | ||
|
eafcbabaa2 | ||
|
14071ea119 | ||
|
421e568232 | ||
|
4efd28c092 | ||
|
d0bbee7e8c | ||
|
7640563991 | ||
|
90cf85c3f0 | ||
|
f1a98693d0 | ||
|
2794d64d3e | ||
|
82743cca92 | ||
|
d0c348e595 | ||
|
f50d3088dc | ||
|
0917fa0d75 | ||
|
cfb73dd534 | ||
|
ef497b7989 | ||
|
9d9341901f | ||
|
155e3d225d | ||
|
ca41f100ab | ||
|
084285a760 | ||
|
982391cd7c | ||
|
d206d0a3ae | ||
|
627ea6c860 | ||
|
bcc76b3764 | ||
|
39692a8b3f | ||
|
eba8b4bf00 | ||
|
f149665660 | ||
|
e3bb64cf35 | ||
|
33f0669100 | ||
|
3a5f3e8b55 | ||
|
a0a90afbc0 | ||
|
2f96cb257c | ||
|
5910bec52e | ||
|
764b1c35cb | ||
|
ee8c9b764d | ||
|
7080f0c35a | ||
|
679d60cd5a | ||
|
bc36c0faed | ||
|
3c073bc360 | ||
|
c52d5e1084 | ||
|
b7bb27fa21 | ||
|
087aaa2f94 | ||
|
474b93a22f | ||
|
0c2f002a7d | ||
|
3d76d83a39 | ||
|
787015f537 | ||
|
fb624fddc4 | ||
|
605ddacb71 | ||
|
71934f05a8 | ||
|
534a0d6836 | ||
|
746b1d0c4d | ||
|
387c80e00a | ||
|
05c914691f | ||
|
94398d70f4 | ||
|
915ddb2b2b | ||
|
b916e7f7ef | ||
|
3cc30f91a9 | ||
|
f4a61b4c70 | ||
|
6eebd693ce | ||
|
bc0ae6be31 | ||
|
c03119d10a | ||
|
e1879ef4d9 | ||
|
b6df727efb | ||
|
fe58b44916 | ||
|
0a2694811d | ||
|
31fe232bac | ||
|
682f6d273c | ||
|
83ddaccf4a | ||
|
e0c0584c59 | ||
|
60f5a52964 | ||
|
7e5866ce3f | ||
|
89b7b56a2c | ||
|
ae54b13d4b | ||
|
927ccc489c | ||
|
21f7722f10 | ||
|
e4afe603f9 | ||
|
30d15a1438 | ||
|
c84586dd66 | ||
|
e9f87c2026 | ||
|
afa27a3c2a | ||
|
ce6078ed94 | ||
|
6d5949ba9c | ||
|
cdb165af7f | ||
|
88a3f8e4aa | ||
|
1c3dc757c3 | ||
|
25866095db | ||
|
b6c8d8e971 | ||
|
ab94b0b231 | ||
|
760bab8f86 | ||
|
817c332d11 | ||
|
05fbc8e6b0 | ||
|
c39301b6da | ||
|
add9a9db9b | ||
|
05123ea6f4 | ||
|
d62ff34a5a | ||
|
a8b8d53d9d | ||
|
0d4ff5a916 | ||
|
8ace41d144 | ||
|
5bb7219f4b | ||
|
f0200ab697 | ||
|
f457a56d4a | ||
|
db086de84a | ||
|
37684c6af0 | ||
|
3c75d4f1dd | ||
|
b19276bb0f | ||
|
774d831fae | ||
|
a1b49d8389 | ||
|
12e2bfc794 | ||
|
6e5abade3c | ||
|
e4e3676095 | ||
|
3ed13150e1 | ||
|
f03e5c6bd1 | ||
|
8496c1cdd3 | ||
|
3c3851c221 | ||
|
05f1e9e3b8 | ||
|
249a1e6d8d | ||
|
e042e0ad32 | ||
|
5db15ca54c | ||
|
069b89b208 | ||
|
63014aeb6b | ||
|
31e21db5b5 | ||
|
7f21872510 | ||
|
27351c9a90 | ||
|
76b918d40e | ||
|
f5bc0b205c | ||
|
b3c253ea2a | ||
|
d17e031259 | ||
|
842363200b | ||
|
d9f9895b2b | ||
|
bc0edd4042 | ||
|
9b82e2df58 | ||
|
3d65341080 | ||
|
80215ea181 | ||
|
78d8526e41 | ||
|
0ddaabe377 | ||
|
9bc6ebde4e | ||
|
011f14d115 | ||
|
62a5cbb5ce | ||
|
5aaf87d612 | ||
|
96b31f3974 | ||
|
09e387bf09 | ||
|
05fe8792ea | ||
|
18ed45597a | ||
|
a200eaacaa | ||
|
f5ad553be3 | ||
|
4f4acc04fe | ||
|
dee0fec9e9 | ||
|
73cc2a140c | ||
|
6058a74da5 | ||
|
bd3b652cfc | ||
|
73429fc720 | ||
|
10478a6b2f | ||
|
e0bc01eea1 | ||
|
2af6d3f6bc | ||
|
cbe5438a31 | ||
|
67c4ad128c | ||
|
870eca0d9f | ||
|
d299458084 | ||
|
e0cf68f1d5 | ||
|
64906a1ba5 | ||
|
e75721016e | ||
|
e0d5b9daf8 | ||
|
5989844f1c | ||
|
14e3f413a2 | ||
|
a97d77064a | ||
|
3342dd4001 | ||
|
785b9811f3 | ||
|
643c77ded0 | ||
|
76f01511a3 | ||
|
dd8727d3ae | ||
|
b933946f33 | ||
|
5d2f9d7a33 | ||
|
3baf14b793 | ||
|
c57e4ba508 | ||
|
98656289ea | ||
|
167a38e27d | ||
|
ba6806df5d | ||
|
fe12101278 | ||
|
d6d7f4e875 | ||
|
63caddea62 | ||
|
36b01fbdcf | ||
|
45a3d8b75a | ||
|
bca62c813d | ||
|
ae1cf74dcd | ||
|
577a8dd005 | ||
|
5900899c01 | ||
|
2dfc468094 | ||
|
98ffe9931d | ||
|
2004c0d739 | ||
|
cd7cb025ad | ||
|
96da267778 | ||
|
5816e410e9 | ||
|
31c98fc0db | ||
|
00bf957b53 | ||
|
5b999c2f7d | ||
|
1cc9d9c071 | ||
|
72fb8460e9 | ||
|
577156fe5f | ||
|
612cc96e41 | ||
|
da3f783a9f | ||
|
b1e8545981 | ||
|
6a2da6dc06 | ||
|
58603e2a5a | ||
|
d97184880c | ||
|
625f40cfa6 | ||
|
49049b8c12 | ||
|
037912ccab | ||
|
8b05b864fb | ||
|
319135c8fe | ||
|
61d9e418e8 | ||
|
475bb2845d | ||
|
42f39de0f9 | ||
|
3898b8e8ab | ||
|
b1fd005c95 | ||
|
cf8fdd3a70 | ||
|
cb754ee125 | ||
|
cea81df969 | ||
|
af1d5fce6e | ||
|
54b86b6131 | ||
|
ec2b83515b | ||
|
2f2724dff5 | ||
|
271fa26890 | ||
|
fe437da751 | ||
|
129876d1be | ||
|
f2ced67a8d | ||
|
787eec8be4 | ||
|
cc39eea999 | ||
|
cbfed99bc6 | ||
|
2b4cd8b2ec | ||
|
b5dc72b126 | ||
|
ab4d2faea3 | ||
|
1677817d9f | ||
|
03854baf53 | ||
|
61dc253de1 | ||
|
a0e8f410d1 | ||
|
2865f63c5d | ||
|
3f19ab1a87 | ||
|
d75fec0cee | ||
|
39570a9663 | ||
|
479c18e21f | ||
|
fd4453d85e | ||
|
7ee7f99780 | ||
|
4c0b8e3113 | ||
|
e0af60d8a7 | ||
|
afcb7f00da | ||
|
e1b06bfce2 | ||
|
8de3f03b49 | ||
|
db8f018b42 | ||
|
59cb2132f2 | ||
|
25f62daf14 | ||
|
05b9dfbe30 | ||
|
3db4e2ee2f | ||
|
86a6a5b826 | ||
|
cc6338d048 | ||
|
57b65726d6 | ||
|
44a736c53b | ||
|
38cbd42d81 | ||
|
28d019f824 | ||
|
54b8e1be89 | ||
|
9778695b4a | ||
|
44b6285268 | ||
|
6c6fb2e287 | ||
|
ecdfde8c38 | ||
|
ea2d5b9d4a | ||
|
1e0522fe8f | ||
|
70858603ed | ||
|
3c508c1d27 | ||
|
5c44db341f | ||
|
cf73363016 | ||
|
351173e554 | ||
|
342432dc76 | ||
|
c4538cada7 | ||
|
de532bb2fc | ||
|
f525afa5de | ||
|
9fba470364 | ||
|
6cd5bf31c9 | ||
|
321c0a8537 | ||
|
b9bc58ef10 | ||
|
7bcf05fd19 | ||
|
f816bdf541 | ||
|
79472552aa | ||
|
c5e5c8288e | ||
|
fd1c7f7169 | ||
|
9212d67e2f | ||
|
f5c74d123a | ||
|
c8421efcd3 | ||
|
f382609d01 | ||
|
f9615c18a1 | ||
|
a74597c7cd | ||
|
d50fbac5f9 | ||
|
95086a75e6 | ||
|
073a96cf63 | ||
|
d3c64bd5b4 | ||
|
7024a7468a | ||
|
62e60e2ba6 | ||
|
fb3860757c | ||
|
e4a8b17522 | ||
|
448df1bb9c | ||
|
bf6900fb2a | ||
|
50552546f3 | ||
|
324fab8186 | ||
|
7ab80f01b5 | ||
|
9ce4a5c7b1 | ||
|
c9a0525a10 | ||
|
83465bb7f5 | ||
|
e8771fb36a | ||
|
d4d03f3d7f | ||
|
d567d667e8 | ||
|
3d55bbbc29 | ||
|
2f8e52f905 | ||
|
a5896ac6b6 | ||
|
94b9d5644c | ||
|
06e5fc233c | ||
|
aefb922a05 | ||
|
a22434fd73 | ||
|
c41846805d | ||
|
b7b45b69a6 | ||
|
ed5528664c | ||
|
fe88d3c225 | ||
|
aed4ee8694 | ||
|
817d9b0d3e | ||
|
df9cfe7840 | ||
|
8cd4578d83 | ||
|
9ca41b9536 | ||
|
559743c911 | ||
|
3a7f26f620 | ||
|
04a0eae241 | ||
|
0500d2fb6e | ||
|
31f1a9e5aa | ||
|
6387aae471 | ||
|
152082e182 | ||
|
08eb2b3df7 | ||
|
846ec87249 | ||
|
62690b5159 | ||
|
719c432ca8 | ||
|
e654616b6d | ||
|
f0473b0320 | ||
|
fcc627e6e1 | ||
|
fe17802cd2 | ||
|
384c05ccc7 | ||
|
193e4f3275 | ||
|
6fd87568e7 | ||
|
484fd68495 | ||
|
792be54443 | ||
|
00df102c29 | ||
|
90e68ddd73 | ||
|
df27f4f118 | ||
|
bee26daf0c | ||
|
b76c738785 | ||
|
8ca9fb0251 | ||
|
3b26a656f7 | ||
|
2f5ac5d993 | ||
|
a2fc9a964b | ||
|
b8a267370d | ||
|
fa3d011f68 | ||
|
a7fc9caacb | ||
|
c284f6dcd4 | ||
|
368d59c3ca | ||
|
94ee82e076 | ||
|
bfefb6e696 | ||
|
95b7601e2b | ||
|
f9c8bd868c | ||
|
a773973b1b | ||
|
a60006366b | ||
|
a66bb7889a | ||
|
adfba06e85 | ||
|
6ee4e954f6 | ||
|
a11d139ff6 | ||
|
85a3e66314 | ||
|
1a3958ed60 | ||
|
743c957918 | ||
|
224a6c192b | ||
|
ae47da3801 | ||
|
a6d669453f | ||
|
0beab9eec4 | ||
|
aa997f1be5 | ||
|
4eb58a70bb | ||
|
5b31d0aa36 | ||
|
79e7c44884 | ||
|
1382c1243a | ||
|
8f2fd9b603 | ||
|
d625b65a09 | ||
|
101e9be7b9 | ||
|
9f93d8f533 | ||
|
6050a59e4a | ||
|
e5b7e29113 | ||
|
ecdd0ce9f2 | ||
|
fc5c598f8f | ||
|
18ebed3c5d | ||
|
822e319efe | ||
|
6d462fc961 | ||
|
4b71c65aea | ||
|
34ab53173d | ||
|
d6be6f79ce | ||
|
87d36f06fd | ||
|
3eb05b4505 | ||
|
0789c6a3d8 | ||
|
b587f076fe | ||
|
a5a7217c8f | ||
|
c0cf55b40b | ||
|
9200ed2216 | ||
|
e1f7dd1372 | ||
|
32833b7301 | ||
|
3302c89284 | ||
|
e18d61b31a | ||
|
61cd1ae525 | ||
|
064608a8ef | ||
|
5a840c88b5 | ||
|
b14c3fe48d | ||
|
4874d55d03 | ||
|
b20e40dd6f | ||
|
bc28a08dd0 | ||
|
0d3010f6fc | ||
|
399a651fa3 | ||
|
30ac5fcb5e | ||
|
92cb5e10be | ||
|
10faa47495 | ||
|
f0bbf2cab0 | ||
|
338e8be327 | ||
|
d4a366aeb1 | ||
|
dea322e2c5 | ||
|
790af0fd72 | ||
|
39008372e5 | ||
|
1026952f26 | ||
|
9631927a8c | ||
|
b0e6ce581a | ||
|
e575323c60 | ||
|
809ac3340c | ||
|
f0af638874 | ||
|
b49148ec54 | ||
|
4e5bfae332 | ||
|
662dc12877 |
@@ -3,7 +3,7 @@ version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
environment:
|
||||
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
||||
working_directory: ~/repo
|
||||
@@ -11,91 +11,76 @@ jobs:
|
||||
- checkout
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
- restore_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-{{ .Branch }}
|
||||
- yarn-packages-master
|
||||
- yarn-packages-
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile
|
||||
command: yarn --frozen-lockfile install
|
||||
- save_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ./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
|
||||
- node_modules/
|
||||
- run: >
|
||||
if [ -z "$(git diff --name-only v2-prototype packages/website)" ]; then
|
||||
yarn build --exclude website
|
||||
else
|
||||
yarn build
|
||||
fi
|
||||
- save_cache:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo
|
||||
test-installation:
|
||||
test-contracts-ganache:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn test:installation
|
||||
test-0xjs:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
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-0xjs-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/0x.js/coverage/lcov.info
|
||||
test-contracts:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
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 contracts
|
||||
test-sol-compiler:
|
||||
test-contracts-geth:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
- image: albrow/0x-devnet
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
# HACK(albrow): we need to sleep 15 seconds to ensure the devnet is
|
||||
# initialized
|
||||
- run: sleep 15 && TEST_PROVIDER=geth yarn wsrun test contracts
|
||||
test-rest:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- 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 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
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-{{ .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
|
||||
test-rest:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
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:
|
||||
@@ -124,27 +109,19 @@ jobs:
|
||||
key: coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/metacoin/coverage/lcov.info
|
||||
lint:
|
||||
static-tests:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn lerna:run lint
|
||||
prettier:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn prettier:ci
|
||||
- run: yarn lerna:run lint
|
||||
submit-coverage:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@@ -156,6 +133,9 @@ jobs:
|
||||
- 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 }}
|
||||
@@ -168,6 +148,9 @@ 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 }}
|
||||
@@ -183,29 +166,18 @@ workflows:
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
# - test-installation:
|
||||
# requires:
|
||||
# - build
|
||||
- test-0xjs:
|
||||
- test-contracts-ganache:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts:
|
||||
requires:
|
||||
- build
|
||||
- test-sol-compiler:
|
||||
- test-contracts-geth:
|
||||
requires:
|
||||
- build
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
- prettier:
|
||||
requires:
|
||||
- build
|
||||
- lint:
|
||||
- static-tests:
|
||||
requires:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-0xjs
|
||||
- test-sol-compiler
|
||||
- test-rest
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -80,12 +80,13 @@ packages/order-watcher/test/artifacts/
|
||||
packages/contract-wrappers/test/artifacts/
|
||||
|
||||
# generated contract wrappers
|
||||
packages/0x.js/src/contract_wrappers/generated/
|
||||
packages/contracts/src/contract_wrappers/generated/
|
||||
packages/0x.js/src/generated_contract_wrappers/
|
||||
packages/contracts/src/generated_contract_wrappers/
|
||||
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/order-utils/src/generated_contract_wrappers/
|
||||
packages/migrations/src/v1/contract_wrappers
|
||||
packages/migrations/src/v2/contract_wrappers
|
||||
|
||||
|
@@ -1,5 +1,14 @@
|
||||
lib
|
||||
.nyc_output
|
||||
/packages/contract-wrappers/src/contract_wrappers/generated/
|
||||
/packages/metacoin/src/contract_wrappers
|
||||
/packages/0x.js/src/generated_contract_wrappers/
|
||||
/packages/contracts/src/generated_contract_wrappers/
|
||||
/packages/fill-scenarios/src/generated_contract_wrappers/
|
||||
/packages/order-watcher/src/generated_contract_wrappers/
|
||||
/packages/order-utils/src/generated_contract_wrappers/
|
||||
/packages/migrations/src/v1/contract_wrappers
|
||||
/packages/migrations/src/v2/contract_wrappers
|
||||
/packages/0x.js/test/artifacts
|
||||
/packages/contracts/src/artifacts
|
||||
/packages/metacoin/artifacts
|
||||
|
21
package.json
21
package.json
@@ -13,20 +13,24 @@
|
||||
"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",
|
||||
"wsrun": "wsrun",
|
||||
"lerna:run": "lerna run",
|
||||
"watch": "wsrun watch $PKG --fast-exit -r --stages --done-criteria='complete|successfully'",
|
||||
"watch": "wsrun watch_without_deps $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"
|
||||
"lint": "wsrun lint $PKG --fast-exit --parallel --exclude-missing",
|
||||
"comment:postinstall": "HACK: For some reason `yarn` is not setting up symlinks properly for order-utils. We temporarily set them manually. Remove this after V2 refactor is complete.",
|
||||
"postinstall": "rm -rf `pwd`/packages/order-utils/node_modules/@0xproject; mkdir `pwd`/packages/order-utils/node_modules/@0xproject; ln -s `pwd`/packages/json-schemas `pwd`/packages/order-utils/node_modules/@0xproject/json-schemas; ln -s `pwd`/packages/types `pwd`/packages/order-utils/node_modules/@0xproject/types; rm -f `pwd`/packages/contracts/node_modules/@0xproject/types; ln -s `pwd`/packages/types `pwd`/packages/contracts/node_modules/@0xproject/types; mkdir -p `pwd`/packages/fill-scenarios/node_modules/@0xproject; ln -s `pwd`/packages/types `pwd`/packages/fill-scenarios/node_modules/@0xproject/types; ln -s `pwd`/packages/order-utils `pwd`/packages/fill-scenarios/node_modules/@0xproject/order-utils"
|
||||
},
|
||||
"config": {
|
||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
||||
@@ -35,10 +39,15 @@
|
||||
"async-child-process": "^1.1.1",
|
||||
"coveralls": "^3.0.0",
|
||||
"ganache-cli": "^6.1.0",
|
||||
"lcov-result-merger": "^2.0.0",
|
||||
"lcov-result-merger": "^3.0.0",
|
||||
"lerna": "^2.5.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"wsrun": "^2.2.0"
|
||||
"wsrun": "^2.2.0",
|
||||
"source-map-support": "^0.5.6"
|
||||
},
|
||||
"resolutions": {
|
||||
"ethereumjs-tx": "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default",
|
||||
"ethers": "0xproject/ethers.js#eip-838-reasons"
|
||||
}
|
||||
}
|
||||
|
@@ -15,20 +15,22 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean generate_contract_wrappers",
|
||||
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --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 .",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && yarn build:all && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"build:all": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||
"pre_build": "run-s generate_contract_wrappers copy_artifacts",
|
||||
"copy_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*",
|
||||
"test:circleci": "run-s test:coverage",
|
||||
"test": "run-s clean test:commonjs",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"clean": "shx rm -rf _bundles lib test_temp scripts src/contract_wrappers/generated",
|
||||
"clean": "shx rm -rf _bundles lib test_temp scripts src/generated_contract_wrappers",
|
||||
"build:umd:prod": "NODE_ENV=production webpack",
|
||||
"build:commonjs": "tsc && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"test:commonjs": "run-s build:commonjs run_mocha",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
|
||||
"docs:stage": "node scripts/stage_docs.js",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES",
|
||||
@@ -44,6 +46,7 @@
|
||||
"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",
|
||||
@@ -51,9 +54,9 @@
|
||||
"../contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts",
|
||||
"../contract-wrappers/src/contract_wrappers/token_wrapper.ts",
|
||||
"../order-watcher/src/order_watcher/order_watcher.ts",
|
||||
"./src/contract_wrappers/generated/ether_token.ts",
|
||||
"./src/contract_wrappers/generated/token.ts",
|
||||
"./src/contract_wrappers/generated/exchange.ts"
|
||||
"./src/generated_contract_wrappers/ether_token.ts",
|
||||
"./src/generated_contract_wrappers/token.ts",
|
||||
"./src/generated_contract_wrappers/exchange.ts"
|
||||
],
|
||||
"s3BucketPath": "s3://doc-jsons/0x.js/",
|
||||
"s3StagingBucketPath": "s3://staging-doc-jsons/0x.js/"
|
||||
@@ -88,7 +91,6 @@
|
||||
"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",
|
||||
@@ -101,13 +103,14 @@
|
||||
"@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-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"
|
||||
},
|
||||
|
@@ -19,7 +19,6 @@ import { OrderWatcher, OrderWatcherConfig } from '@0xproject/order-watcher';
|
||||
import { ECSignature, Order, Provider, SignedOrder, TransactionReceiptWithDecodedLogs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
|
||||
|
@@ -1,16 +1,3 @@
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
ContractEventArg,
|
||||
ExchangeContractErrs,
|
||||
FilterObject,
|
||||
LogWithDecodedArgs,
|
||||
Order,
|
||||
OrderState,
|
||||
SignedOrder,
|
||||
} from '@0xproject/types';
|
||||
|
||||
export enum InternalZeroExError {
|
||||
NoAbiDecoder = 'NO_ABI_DECODER',
|
||||
ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY',
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
TESTRPC_NETWORK_ID: 50,
|
||||
|
@@ -1,14 +1,12 @@
|
||||
import { ContractWrappers } from '@0xproject/contract-wrappers';
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import 'mocha';
|
||||
import * as path from 'path';
|
||||
import * as Sinon from 'sinon';
|
||||
|
||||
import { ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx } from '../src';
|
||||
import { ApprovalContractEventArgs, LogWithDecodedArgs, TokenEvents, ZeroEx } from '../src';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
@@ -137,6 +135,7 @@ describe('ZeroEx library', () => {
|
||||
const proxyAddress = zeroEx.proxy.getContractAddress();
|
||||
const txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(zrxTokenAddress, coinbase);
|
||||
const txReceiptWithDecodedLogs = await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const log = txReceiptWithDecodedLogs.logs[0] as LogWithDecodedArgs<ApprovalContractEventArgs>;
|
||||
expect(log.event).to.be.equal(TokenEvents.Approval);
|
||||
expect(log.args._owner).to.be.equal(coinbase);
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import * as fs from 'fs';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ZeroEx } from '../src';
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { runV1MigrationsAsync } from '@0xproject/migrations';
|
||||
import * as path from 'path';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
import { provider } from './utils/web3_wrapper';
|
||||
|
||||
before('migrate contracts', async function(): Promise<void> {
|
||||
@@ -11,7 +9,7 @@ before('migrate contracts', async function(): Promise<void> {
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_ESTIMATE,
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
const artifactsDir = `../migrations/artifacts/1.0.0`;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import { Provider } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
|
@@ -4,8 +4,7 @@ This package allows you to generate TypeScript contract wrappers from ABI files.
|
||||
It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach.
|
||||
You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.
|
||||
|
||||
For an example of the generated [wrapper files](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js.
|
||||
[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate those files.
|
||||
[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate the contract wrappers used by 0x.js.e
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -45,7 +44,7 @@ You need to also specify the location of your main template used for every contr
|
||||
|
||||
## How to write custom templates?
|
||||
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) and start adjusting them for your needs.
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates) and start adjusting them for your needs.
|
||||
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
|
||||
You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available.
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"lint": "tslint --project .",
|
||||
"clean": "shx rm -rf lib scripts",
|
||||
"build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts",
|
||||
@@ -27,9 +27,9 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@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",
|
||||
|
@@ -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';
|
||||
@@ -12,7 +12,7 @@ import * as yargs from 'yargs';
|
||||
|
||||
import toSnakeCase = require('to-snake-case');
|
||||
|
||||
import { ContextData, ContractsBackend, Method, ParamKind } from './types';
|
||||
import { ContextData, ContractsBackend, ParamKind } from './types';
|
||||
import { utils } from './utils';
|
||||
|
||||
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { EventAbi, MethodAbi } from '@0xproject/types';
|
||||
import { EventAbi, MethodAbi } from 'ethereum-types';
|
||||
|
||||
export enum ParamKind {
|
||||
Input = 'input',
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { AbiType, ConstructorAbi, DataItem } from '@0xproject/types';
|
||||
import { AbiType, ConstructorAbi, DataItem } from 'ethereum-types';
|
||||
import * as fs from 'fs';
|
||||
import * as _ from 'lodash';
|
||||
import * as path from 'path';
|
||||
@@ -56,7 +56,7 @@ export const utils = {
|
||||
const componentType = `${component.name}: ${componentValueType}`;
|
||||
return componentType;
|
||||
});
|
||||
const tsType = `{${componentsType}}`;
|
||||
const tsType = `{${componentsType.join(';')}}`;
|
||||
return tsType;
|
||||
}
|
||||
throw new Error(`Unknown Solidity type found: ${solType}`);
|
||||
|
@@ -8,13 +8,14 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"clean": "shx rm -rf lib test_temp scripts",
|
||||
"lint": "tslint --project .",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js --exit",
|
||||
"prepublishOnly": "run-p build",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
|
@@ -8,15 +8,16 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts",
|
||||
"clean": "shx rm -rf lib scripts",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js --bail --exit",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"lint": "tslint --project .",
|
||||
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/*",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
@@ -42,7 +43,7 @@
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { abiUtils, BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import {
|
||||
AbiDefinition,
|
||||
AbiType,
|
||||
@@ -8,9 +10,7 @@ import {
|
||||
Provider,
|
||||
TxData,
|
||||
TxDataPayable,
|
||||
} from '@0xproject/types';
|
||||
import { abiUtils, BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
} from 'ethereum-types';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -37,13 +37,14 @@ export class BaseContract {
|
||||
protected static _lowercaseAddress(type: string, value: string): string {
|
||||
return type === 'address' ? value.toLowerCase() : value;
|
||||
}
|
||||
protected static _bigNumberToString(type: string, value: any): any {
|
||||
protected static _bigNumberToString(_type: string, value: any): any {
|
||||
return _.isObject(value) && value.isBigNumber ? value.toString() : value;
|
||||
}
|
||||
protected static _lookupConstructorAbi(abi: ContractAbi): ConstructorAbi {
|
||||
const constructorAbiIfExists = _.find(
|
||||
abi,
|
||||
(abiDefinition: AbiDefinition) => abiDefinition.type === AbiType.Constructor,
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
) as ConstructorAbi | undefined;
|
||||
if (!_.isUndefined(constructorAbiIfExists)) {
|
||||
return constructorAbiIfExists;
|
||||
@@ -59,7 +60,7 @@ export class BaseContract {
|
||||
return defaultConstructorAbi;
|
||||
}
|
||||
}
|
||||
protected static _bnToBigNumber(type: string, value: any): any {
|
||||
protected static _bnToBigNumber(_type: string, value: any): any {
|
||||
return _.isObject(value) && value._bn ? new BigNumber(value.toString()) : value;
|
||||
}
|
||||
protected static async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>(
|
||||
@@ -79,8 +80,7 @@ export class BaseContract {
|
||||
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
|
||||
} as any;
|
||||
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
|
||||
const estimatedGas = await estimateGasAsync(txData);
|
||||
txDataWithDefaults.gas = estimatedGas;
|
||||
txDataWithDefaults.gas = await estimateGasAsync(txData);
|
||||
}
|
||||
return txDataWithDefaults;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { DataItem } from '@0xproject/types';
|
||||
import { DataItem } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
// tslint:disable-next-line:completed-docs
|
||||
|
@@ -15,13 +15,14 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"clean": "shx rm -rf lib test_temp scripts",
|
||||
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
|
||||
"lint": "tslint --project .",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js --exit",
|
||||
"test": "run-s clean build copy_test_fixtures run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js --exit",
|
||||
"test": "run-s copy_test_fixtures run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
|
@@ -48,7 +48,7 @@ export class HttpClient implements Client {
|
||||
return '';
|
||||
}
|
||||
// format params into a form the api expects
|
||||
const formattedParams = _.mapKeys(params, (value: any, key: string) => {
|
||||
const formattedParams = _.mapKeys(params, (_value: any, key: string) => {
|
||||
return _.get(OPTS_TO_QUERY_FIELD_MAP, key, key);
|
||||
});
|
||||
// stringify the formatted object
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Order, SignedOrder } from '@0xproject/types';
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export interface Client {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { assert } from '@0xproject/assert';
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { FeesResponse, OrderbookResponse, TokenPairsItem } from '../types';
|
||||
|
||||
|
@@ -78,7 +78,7 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
connection.on(WebsocketConnectionEventType.Error, wsError => {
|
||||
handler.onError(this, subscriptionOpts, wsError);
|
||||
});
|
||||
connection.on(WebsocketConnectionEventType.Close, (code: number, desc: string) => {
|
||||
connection.on(WebsocketConnectionEventType.Close, (_code: number, _desc: string) => {
|
||||
handler.onClose(this, subscriptionOpts);
|
||||
});
|
||||
connection.on(WebsocketConnectionEventType.Message, message => {
|
||||
|
@@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Expose 'abi' ContractAbi property on all contract wrappers"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.0.2",
|
||||
"changes": [
|
||||
|
@@ -11,18 +11,20 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean generate_contract_wrappers",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"pre_build": "run-s generate_contract_wrappers update_test_artifacts update_compact_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --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 .",
|
||||
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"test:circleci": "run-s test:coverage",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/1.0.0/$i.json test/artifacts; done;",
|
||||
"update_compact_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",
|
||||
"update_test_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/1.0.0/$i.json test/artifacts; done;",
|
||||
"clean": "shx rm -rf _bundles lib test_temp scripts test/artifacts src/contract_wrappers/generated",
|
||||
"build": "tsc && yarn update_artifacts && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
|
||||
},
|
||||
"config": {
|
||||
@@ -67,7 +69,6 @@
|
||||
"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",
|
||||
@@ -80,11 +81,12 @@
|
||||
"@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/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",
|
||||
|
@@ -0,0 +1,11 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void;
|
||||
public abstract deleteBalance(tokenAddress: string, userAddress: string): void;
|
||||
public abstract setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void;
|
||||
public abstract deleteProxyAllowance(tokenAddress: string, userAddress: string): void;
|
||||
public abstract deleteAll(): void;
|
||||
}
|
@@ -7,7 +7,7 @@ import {
|
||||
LogWithDecodedArgs,
|
||||
RawLog,
|
||||
} from '@0xproject/types';
|
||||
import { AbiDecoder, intervalUtils } from '@0xproject/utils';
|
||||
import { intervalUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
|
||||
import * as _ from 'lodash';
|
||||
@@ -35,7 +35,8 @@ const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
|
||||
Exchange: ContractWrappersError.ExchangeContractDoesNotExist,
|
||||
};
|
||||
|
||||
export class ContractWrapper {
|
||||
export abstract class ContractWrapper {
|
||||
public abstract abi: ContractAbi;
|
||||
protected _web3Wrapper: Web3Wrapper;
|
||||
protected _networkId: number;
|
||||
private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
|
||||
@@ -185,6 +186,7 @@ export class ContractWrapper {
|
||||
this._unsubscribe(filterToken, err);
|
||||
});
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _setNetworkId(networkId: number): void {
|
||||
this._networkId = networkId;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { ContractAbi, LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -17,6 +17,7 @@ import { TokenWrapper } from './token_wrapper';
|
||||
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
|
||||
*/
|
||||
export class EtherTokenWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.EtherToken.abi;
|
||||
private _etherTokenContractsByAddress: {
|
||||
[address: string]: EtherTokenContract;
|
||||
} = {};
|
||||
@@ -181,6 +182,7 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
: networkSpecificArtifact.address;
|
||||
return contractAddressIfExists;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
this.unsubscribeAll();
|
||||
this._etherTokenContractsByAddress = {};
|
||||
|
@@ -2,24 +2,24 @@ import { schemas } from '@0xproject/json-schemas';
|
||||
import { formatters, getOrderHashHex, OrderStateUtils } from '@0xproject/order-utils';
|
||||
import {
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
DecodedLogArgs,
|
||||
ECSignature,
|
||||
ExchangeContractErrs,
|
||||
LogEntry,
|
||||
LogWithDecodedArgs,
|
||||
Order,
|
||||
OrderAddresses,
|
||||
OrderState,
|
||||
OrderValues,
|
||||
SignedOrder,
|
||||
} from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher';
|
||||
import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||
import {
|
||||
BlockRange,
|
||||
EventCallback,
|
||||
@@ -35,7 +35,6 @@ import { assert } from '../utils/assert';
|
||||
import { decorators } from '../utils/decorators';
|
||||
import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator';
|
||||
import { OrderValidationUtils } from '../utils/order_validation_utils';
|
||||
import { utils } from '../utils/utils';
|
||||
|
||||
import { ContractWrapper } from './contract_wrapper';
|
||||
import {
|
||||
@@ -56,8 +55,9 @@ interface ExchangeContractErrCodesToMsgs {
|
||||
* events of the 0x Exchange smart contract.
|
||||
*/
|
||||
export class ExchangeWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.Exchange.abi;
|
||||
private _exchangeContractIfExists?: ExchangeContract;
|
||||
private _orderValidationUtils: OrderValidationUtils;
|
||||
private _orderValidationUtilsIfExists?: OrderValidationUtils;
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = {
|
||||
[ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
|
||||
@@ -78,7 +78,6 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
) {
|
||||
super(web3Wrapper, networkId);
|
||||
this._tokenWrapper = tokenWrapper;
|
||||
this._orderValidationUtils = new OrderValidationUtils(this);
|
||||
this._contractAddressIfExists = contractAddressIfExists;
|
||||
this._zrxContractAddressIfExists = zrxContractAddressIfExists;
|
||||
}
|
||||
@@ -180,8 +179,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -255,9 +259,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
if (shouldValidate) {
|
||||
let filledTakerTokenAmount = new BigNumber(0);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const signedOrder of signedOrders) {
|
||||
const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const singleFilledTakerTokenAmount = await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount.minus(filledTakerTokenAmount),
|
||||
@@ -348,9 +357,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
@@ -424,8 +438,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -486,9 +505,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
@@ -736,8 +760,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
zrxTokenAddress,
|
||||
@@ -762,8 +791,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -809,8 +843,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -888,6 +927,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
const contractAddress = this._getContractAddress(artifacts.ZRX, this._zrxContractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
// tslint:disable:no-unused-variable
|
||||
private _invalidateContractInstances(): void {
|
||||
this.unsubscribeAll();
|
||||
delete this._exchangeContractIfExists;
|
||||
@@ -919,6 +959,15 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
||||
return orderHashHex;
|
||||
}
|
||||
private async _getOrderValidationUtilsAsync(): Promise<OrderValidationUtils> {
|
||||
if (!_.isUndefined(this._orderValidationUtilsIfExists)) {
|
||||
return this._orderValidationUtilsIfExists;
|
||||
}
|
||||
const exchangeContract = await this._getExchangeContractAsync();
|
||||
this._orderValidationUtilsIfExists = new OrderValidationUtils(exchangeContract);
|
||||
return this._orderValidationUtilsIfExists;
|
||||
}
|
||||
// tslint:enable:no-unused-variable
|
||||
private async _getExchangeContractAsync(): Promise<ExchangeContract> {
|
||||
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
||||
return this._exchangeContractIfExists;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Token } from '@0xproject/types';
|
||||
import { ContractAbi, Token } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -14,6 +14,7 @@ import { TokenRegistryContract } from './generated/token_registry';
|
||||
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
|
||||
*/
|
||||
export class TokenRegistryWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.TokenRegistry.abi;
|
||||
private _tokenRegistryContractIfExists?: TokenRegistryContract;
|
||||
private _contractAddressIfExists?: string;
|
||||
private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined {
|
||||
@@ -108,6 +109,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
||||
const contractAddress = this._getContractAddress(artifacts.TokenRegistry, this._contractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
delete this._tokenRegistryContractIfExists;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { ContractAbi } from '@0xproject/types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
@@ -11,6 +12,7 @@ import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
|
||||
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
|
||||
*/
|
||||
export class TokenTransferProxyWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.TokenTransferProxy.abi;
|
||||
private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract;
|
||||
private _contractAddressIfExists?: string;
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
|
||||
@@ -49,6 +51,7 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
||||
const contractAddress = this._getContractAddress(artifacts.TokenTransferProxy, this._contractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
delete this._tokenTransferProxyContractIfExists;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { ContractAbi, LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -26,6 +26,7 @@ import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
|
||||
* to the 0x Proxy smart contract.
|
||||
*/
|
||||
export class TokenWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.Token.abi;
|
||||
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
private _tokenContractsByAddress: { [address: string]: TokenContract };
|
||||
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
||||
@@ -414,6 +415,7 @@ export class TokenWrapper extends ContractWrapper {
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstances(): void {
|
||||
this.unsubscribeAll();
|
||||
this._tokenContractsByAddress = {};
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
|
||||
/**
|
||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||
*/
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceFetcher {
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
private _defaultBlock: BlockParamLiteral;
|
||||
private _balance: {
|
||||
|
@@ -2,11 +2,7 @@ import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
ContractEventArg,
|
||||
ExchangeContractErrs,
|
||||
FilterObject,
|
||||
LogEntryEvent,
|
||||
LogWithDecodedArgs,
|
||||
Order,
|
||||
@@ -158,7 +154,7 @@ export interface MethodOpts {
|
||||
|
||||
/**
|
||||
* gasPrice: Gas price in Wei to use for a transaction
|
||||
* gasLimit: The amount of gas to send with a transaction
|
||||
* gasLimit: The amount of gas to send with a transaction (in Gwei)
|
||||
*/
|
||||
export interface TransactionOpts {
|
||||
gasPrice?: BigNumber;
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { assert as sharedAssert } from '@0xproject/assert';
|
||||
// We need those two unused imports because they're actually used by sharedAssert which gets injected here
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
// tslint:disable:no-unused-variable
|
||||
import { Schema } from '@0xproject/json-schemas';
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
import { ECSignature } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
import { isValidSignature } from '@0xproject/order-utils';
|
||||
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../types';
|
||||
import { constants } from '../utils/constants';
|
||||
|
||||
@@ -36,8 +35,7 @@ const ERR_MSG_MAPPING = {
|
||||
};
|
||||
|
||||
export class ExchangeTransferSimulator {
|
||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private _store: AbstractBalanceAndProxyAllowanceLazyStore;
|
||||
private static _throwValidationError(
|
||||
failureReason: FailureReason,
|
||||
tradeSide: TradeSide,
|
||||
@@ -46,9 +44,8 @@ export class ExchangeTransferSimulator {
|
||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) {
|
||||
this._store = store;
|
||||
}
|
||||
/**
|
||||
* Simulates transferFrom call performed by a proxy
|
||||
@@ -92,7 +89,7 @@ export class ExchangeTransferSimulator {
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// tslint:disable:no-unused-variable
|
||||
import {
|
||||
ConstructorAbi,
|
||||
ContractAbi,
|
||||
@@ -7,6 +8,7 @@ import {
|
||||
LogEntry,
|
||||
MethodAbi,
|
||||
} from '@0xproject/types';
|
||||
// tslint:enable:no-unused-variable
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as jsSHA3 from 'js-sha3';
|
||||
import * as _ from 'lodash';
|
||||
|
@@ -3,15 +3,15 @@ import { ExchangeContractErrs, Order, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||
import { ContractWrappersError, TradeSide, TransferType } from '../types';
|
||||
import { ExchangeContract } from '../contract_wrappers/generated/exchange';
|
||||
import { TradeSide, TransferType } from '../types';
|
||||
import { constants } from '../utils/constants';
|
||||
import { utils } from '../utils/utils';
|
||||
|
||||
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||
|
||||
export class OrderValidationUtils {
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
private _exchangeContract: ExchangeContract;
|
||||
public static validateCancelOrderThrowIfInvalid(
|
||||
order: Order,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
@@ -104,8 +104,8 @@ export class OrderValidationUtils {
|
||||
.round(0);
|
||||
return fillMakerTokenAmount;
|
||||
}
|
||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
constructor(exchangeContract: ExchangeContract) {
|
||||
this._exchangeContract = exchangeContract;
|
||||
}
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
@@ -114,7 +114,9 @@ export class OrderValidationUtils {
|
||||
expectedFillTakerTokenAmount?: BigNumber,
|
||||
): Promise<void> {
|
||||
const orderHash = getOrderHashHex(signedOrder);
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash,
|
||||
);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
@@ -146,7 +148,9 @@ export class OrderValidationUtils {
|
||||
if (!isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
||||
throw new Error(OrderError.InvalidSignature);
|
||||
}
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash,
|
||||
);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
@@ -167,7 +171,7 @@ export class OrderValidationUtils {
|
||||
zrxTokenAddress,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||
const wouldRoundingErrorOccur = await this._exchangeContract.isRoundingError.callAsync(
|
||||
filledTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
|
@@ -1,9 +1,6 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const utils = {
|
||||
spawnSwitchErr(name: string, value: any): Error {
|
||||
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
||||
},
|
||||
getCurrentUnixTimestampSec(): BigNumber {
|
||||
const milisecondsInSecond = 1000;
|
||||
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import * as fs from 'fs';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ContractWrappers } from '../src';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { DoneCallback } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BlockParamLiteral, Token } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ContractWrappers, ExchangeContractErrs } from '../src';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||
|
||||
@@ -44,7 +45,11 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
describe('#transferFromAsync', () => {
|
||||
beforeEach(() => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
contractWrappers.token,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
});
|
||||
it("throws if the user doesn't have enough allowance", async () => {
|
||||
return expect(
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { FillScenarios } from '@0xproject/fill-scenarios';
|
||||
import { getOrderHashHex } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral, DoneCallback, OrderState } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import 'mocha';
|
||||
|
||||
|
@@ -1,17 +1,15 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { runV1MigrationsAsync } from '@0xproject/migrations';
|
||||
import * as path from 'path';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
import { provider } from './utils/web3_wrapper';
|
||||
|
||||
before('migrate contracts', async function(): Promise<void> {
|
||||
// HACK: Since the migrations take longer then our global mocha timeout limit
|
||||
// we manually increase it for this before hook.
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
const mochaTestTimeoutMs = 50000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_ESTIMATE,
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
const artifactsDir = `../migrations/artifacts/1.0.0`;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { FillScenarios } from '@0xproject/fill-scenarios';
|
||||
import { OrderError } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral } from '@0xproject/types';
|
||||
@@ -7,7 +7,8 @@ import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
import * as Sinon from 'sinon';
|
||||
|
||||
import { ContractWrappers, ContractWrappersError, ExchangeContractErrs, SignedOrder, Token } from '../src';
|
||||
import { ContractWrappers, ExchangeContractErrs, SignedOrder, Token } from '../src';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||
import { OrderValidationUtils } from '../src/utils/order_validation_utils';
|
||||
@@ -332,7 +333,11 @@ describe('OrderValidation', () => {
|
||||
return Sinon.match((value: BigNumber) => value.eq(expected));
|
||||
};
|
||||
beforeEach('create exchangeTransferSimulator', async () => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
contractWrappers.token,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
transferFromAsync = Sinon.spy();
|
||||
exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { DoneCallback } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { EmptyWalletSubprovider } from '@0xproject/subproviders';
|
||||
import { DoneCallback, Provider } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
@@ -218,7 +218,6 @@ describe('TokenWrapper', () => {
|
||||
describe('With provider without accounts', () => {
|
||||
let zeroExContractWithoutAccounts: ContractWrappers;
|
||||
before(async () => {
|
||||
const hasAddresses = false;
|
||||
const emptyWalletProvider = addEmptyWalletSubprovider(provider);
|
||||
zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config);
|
||||
});
|
||||
@@ -361,7 +360,6 @@ describe('TokenWrapper', () => {
|
||||
describe('With provider without accounts', () => {
|
||||
let zeroExContractWithoutAccounts: ContractWrappers;
|
||||
before(async () => {
|
||||
const hasAddresses = false;
|
||||
const emptyWalletProvider = addEmptyWalletSubprovider(provider);
|
||||
zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config);
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import { Provider } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
|
@@ -2,15 +2,16 @@
|
||||
* 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
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma whitespace
|
||||
// tslint:disable:no-unused-variable
|
||||
import { BaseContract } from '@0xproject/base-contract';
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, DataItem, MethodAbi, Provider, TxData, TxDataPayable } from '@0xproject/types';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, DataItem, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
|
||||
import { BigNumber, classUtils, logUtils, promisify } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
{{#if events}}
|
||||
export type {{contractName}}ContractEventArgs =
|
||||
@@ -83,7 +84,7 @@ export class {{contractName}}Contract extends BaseContract {
|
||||
return contractInstance;
|
||||
}
|
||||
constructor(abi: ContractAbi, address: string, provider: Provider, txDefaults?: Partial<TxData>) {
|
||||
super("{{contractName}}", abi, address, provider, txDefaults);
|
||||
super('{{contractName}}', abi, address, provider, txDefaults);
|
||||
classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']);
|
||||
}
|
||||
} // tslint:disable:max-file-line-count
|
||||
|
@@ -18,7 +18,7 @@ async callAsync(
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
)
|
||||
);
|
||||
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
|
||||
let resultArray = ethersFunction.parse(rawCallResult);
|
||||
const outputAbi = (_.find(self.abi, {name: '{{this.name}}'}) as MethodAbi).outputs;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export interface {{name}}ContractEventArgs {
|
||||
export interface {{name}}ContractEventArgs extends DecodedLogArgs {
|
||||
{{#each inputs}}
|
||||
{{name}}: {{#returnType type components}}{{/returnType}};
|
||||
{{/each}}
|
||||
|
@@ -63,3 +63,12 @@ yarn lint
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
### Run Tests Against Geth
|
||||
|
||||
Follow the instructions in the README for the devnet package to start the
|
||||
devnet.
|
||||
|
||||
```bash
|
||||
TEST_PROVIDER=geth yarn test
|
||||
```
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"compilerSettings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 0
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
@@ -21,6 +21,7 @@
|
||||
"contracts": [
|
||||
"AssetProxyOwner",
|
||||
"DummyERC20Token",
|
||||
"DummyERC721Receiver",
|
||||
"DummyERC721Token",
|
||||
"ERC20Proxy",
|
||||
"ERC721Proxy",
|
||||
@@ -28,11 +29,14 @@
|
||||
"MixinAuthorizable",
|
||||
"MultiSigWallet",
|
||||
"MultiSigWalletWithTimeLock",
|
||||
"TestAssetDataDecoders",
|
||||
"TestAssetProxyDispatcher",
|
||||
"TestLibBytes",
|
||||
"TestLibMem",
|
||||
"TestLibs",
|
||||
"TestSignatureValidator",
|
||||
"TokenRegistry",
|
||||
"Whitelist",
|
||||
"WETH9",
|
||||
"ZRXToken"
|
||||
]
|
||||
|
@@ -11,25 +11,29 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean compile copy_artifacts generate_contract_wrappers",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc",
|
||||
"pre_build": "run-s compile copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/2.0.0/**/*' ./lib/src/artifacts;",
|
||||
"build": "tsc",
|
||||
"test": "run-s build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"clean": "shx rm -rf lib src/contract_wrappers/generated",
|
||||
"clean": "shx rm -rf lib src/generated_contract_wrappers",
|
||||
"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 .",
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock||TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TokenRegistry|WETH9|ZRXToken).json"
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetDataDecoders|TestAssetProxyDispatcher|TestLibBytes|TestLibMem|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -48,7 +52,9 @@
|
||||
"@0xproject/subproviders": "^0.10.1",
|
||||
"@0xproject/sol-cov": "^0.0.11",
|
||||
"@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",
|
||||
@@ -58,7 +64,6 @@
|
||||
"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",
|
||||
"tslint": "5.8.0",
|
||||
@@ -67,12 +72,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/order-utils": "^0.0.5",
|
||||
"@0xproject/order-utils": "^0.0.6",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/types": "^1.0.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",
|
||||
|
@@ -20,9 +20,9 @@ pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
||||
import "./MixinAssetProxy.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
||||
|
||||
contract ERC20Proxy is
|
||||
LibBytes,
|
||||
@@ -33,40 +33,54 @@ contract ERC20Proxy is
|
||||
// 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 assetData 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,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
require(
|
||||
uint8(assetMetadata[0]) == PROXY_ID,
|
||||
PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// Decode metadata.
|
||||
require(
|
||||
assetMetadata.length == 21,
|
||||
INVALID_METADATA_LENGTH
|
||||
);
|
||||
address token = readAddress(assetMetadata, 1);
|
||||
// Decode asset data.
|
||||
address token = readAddress(assetData, 0);
|
||||
|
||||
// Transfer tokens.
|
||||
bool success = IERC20Token(token).transferFrom(from, to, amount);
|
||||
// We do a raw call so we can check the success separate
|
||||
// from the return data.
|
||||
bool success = token.call(abi.encodeWithSelector(
|
||||
IERC20Token(token).transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
));
|
||||
require(
|
||||
success == true,
|
||||
success,
|
||||
TRANSFER_FAILED
|
||||
);
|
||||
|
||||
// Check return data.
|
||||
// If there is no return data, we assume the token incorrectly
|
||||
// does not return a bool. In this case we expect it to revert
|
||||
// on failure, which was handled above.
|
||||
// If the token does return data, we require that it is a single
|
||||
// value that evaluates to true.
|
||||
assembly {
|
||||
if returndatasize {
|
||||
success := 0
|
||||
if eq(returndatasize, 32) {
|
||||
// First 64 bytes of memory are reserved scratch space
|
||||
returndatacopy(0, 0, 32)
|
||||
success := mload(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
require(
|
||||
success,
|
||||
TRANSFER_FAILED
|
||||
);
|
||||
}
|
||||
|
@@ -20,9 +20,9 @@ pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "../../tokens/ERC721Token/ERC721Token.sol";
|
||||
import "./MixinAssetProxy.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../../tokens/ERC721Token/ERC721Token.sol";
|
||||
|
||||
contract ERC721Proxy is
|
||||
LibBytes,
|
||||
@@ -33,48 +33,39 @@ contract ERC721Proxy is
|
||||
// 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 assetData 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,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
require(
|
||||
uint8(assetMetadata[0]) == PROXY_ID,
|
||||
PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// There exists only 1 of each token.
|
||||
require(
|
||||
amount == 1,
|
||||
INVALID_TRANSFER_AMOUNT
|
||||
INVALID_AMOUNT
|
||||
);
|
||||
|
||||
// Decode asset data.
|
||||
(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
// Decode metadata
|
||||
require(
|
||||
assetMetadata.length == 53,
|
||||
INVALID_METADATA_LENGTH
|
||||
);
|
||||
address token = readAddress(assetMetadata, 1);
|
||||
uint256 tokenId = readUint256(assetMetadata, 21);
|
||||
|
||||
// Transfer token.
|
||||
// Either succeeds or throws.
|
||||
// @TODO: Call safeTransferFrom if there is additional
|
||||
// data stored in `assetMetadata`.
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
// Transfer token. Saves gas by calling safeTransferFrom only
|
||||
// when there is receiverData present. Either succeeds or throws.
|
||||
if (receiverData.length > 0) {
|
||||
ERC721Token(token).safeTransferFrom(from, to, tokenId, receiverData);
|
||||
} else {
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
@@ -86,4 +77,34 @@ contract ERC721Proxy is
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function decodeERC721AssetData(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
// Decode asset data.
|
||||
token = readAddress(assetData, 0);
|
||||
tokenId = readUint256(assetData, 20);
|
||||
if (assetData.length > 52) {
|
||||
receiverData = readBytes(assetData, 52);
|
||||
}
|
||||
|
||||
return (
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -19,29 +19,30 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./mixins/MAssetProxy.sol";
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
import "./mixins/MAssetProxy.sol";
|
||||
|
||||
contract MixinAssetProxy is
|
||||
contract MixinAssetProxy is
|
||||
MAuthorizable,
|
||||
MAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData 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,
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyAuthorized
|
||||
{
|
||||
transferFromInternal(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
@@ -49,21 +50,22 @@ contract MixinAssetProxy is
|
||||
}
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param assetData 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,
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts)
|
||||
uint256[] memory amounts
|
||||
)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
for (uint256 i = 0; i < assetMetadata.length; i++) {
|
||||
for (uint256 i = 0; i < assetData.length; i++) {
|
||||
transferFromInternal(
|
||||
assetMetadata[i],
|
||||
assetData[i],
|
||||
from[i],
|
||||
to[i],
|
||||
amounts[i]
|
||||
|
@@ -19,21 +19,16 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
import "./libs/LibAssetProxyErrors.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
|
||||
contract MixinAuthorizable is
|
||||
LibAssetProxyErrors,
|
||||
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(
|
||||
@@ -87,7 +82,10 @@ contract MixinAuthorizable is
|
||||
/// @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)
|
||||
function removeAuthorizedAddressAtIndex(
|
||||
address target,
|
||||
uint256 index
|
||||
)
|
||||
external
|
||||
{
|
||||
require(
|
||||
@@ -96,7 +94,7 @@ contract MixinAuthorizable is
|
||||
);
|
||||
require(
|
||||
authorities[index] == target,
|
||||
INDEX_ADDRESS_MISMATCH
|
||||
AUTHORIZED_ADDRESS_MISMATCH
|
||||
);
|
||||
|
||||
delete authorized[target];
|
||||
|
@@ -26,27 +26,29 @@ contract IAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData 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,
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
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 assetData 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,
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts)
|
||||
uint256[] memory amounts
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
|
@@ -45,6 +45,9 @@ contract IAuthorizable is
|
||||
/// @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)
|
||||
function removeAuthorizedAddressAtIndex(
|
||||
address target,
|
||||
uint256 index
|
||||
)
|
||||
external;
|
||||
}
|
||||
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
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 LibAssetProxyErrors {
|
||||
/// Authorizable errors ///
|
||||
string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED"; // Sender not authorized to call this method.
|
||||
string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED"; // Target address not authorized to call this method.
|
||||
string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED"; // Target address must not already be authorized.
|
||||
string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS"; // Specified array index is out of bounds.
|
||||
string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH"; // Address at index does not match given target address.
|
||||
|
||||
/// AssetProxy errors ///
|
||||
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
|
||||
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
|
||||
}
|
@@ -26,14 +26,15 @@ contract MAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData 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,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
||||
|
@@ -38,5 +38,5 @@ contract MAuthorizable is
|
||||
);
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized { _; }
|
||||
modifier onlyAuthorized { revert(); _; }
|
||||
}
|
||||
|
@@ -40,11 +40,11 @@ contract Exchange is
|
||||
string constant public VERSION = "2.0.1-alpha";
|
||||
|
||||
// Mixins are instantiated in the order they are inherited
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
MixinExchangeCore()
|
||||
MixinMatchOrders()
|
||||
MixinSettlement(_zrxProxyData)
|
||||
MixinSettlement(_zrxAssetData)
|
||||
MixinSignatureValidator()
|
||||
MixinTransactions()
|
||||
MixinAssetProxyDispatcher()
|
||||
|
@@ -19,13 +19,15 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
import "../AssetProxy/interfaces/IAssetProxy.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
import "../AssetProxy/interfaces/IAssetProxy.sol";
|
||||
|
||||
contract MixinAssetProxyDispatcher is
|
||||
LibExchangeErrors,
|
||||
Ownable,
|
||||
LibBytes,
|
||||
LibExchangeErrors,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
||||
@@ -39,14 +41,16 @@ contract MixinAssetProxyDispatcher is
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy)
|
||||
address oldAssetProxy
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
// Ensure the existing asset proxy is not unintentionally overwritten
|
||||
address currentAssetProxy = address(assetProxies[assetProxyId]);
|
||||
require(
|
||||
oldAssetProxy == address(assetProxies[assetProxyId]),
|
||||
OLD_ASSET_PROXY_MISMATCH
|
||||
oldAssetProxy == currentAssetProxy,
|
||||
ASSET_PROXY_MISMATCH
|
||||
);
|
||||
|
||||
IAssetProxy assetProxy = IAssetProxy(newAssetProxy);
|
||||
@@ -56,7 +60,7 @@ contract MixinAssetProxyDispatcher is
|
||||
uint8 newAssetProxyId = assetProxy.getProxyId();
|
||||
require(
|
||||
newAssetProxyId == assetProxyId,
|
||||
NEW_ASSET_PROXY_MISMATCH
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
}
|
||||
|
||||
@@ -78,29 +82,26 @@ contract MixinAssetProxyDispatcher is
|
||||
}
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param assetProxyId Id of assetProxy to dispach to.
|
||||
/// @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,
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Do nothing if no amount should be transferred.
|
||||
if (amount > 0) {
|
||||
// Lookup asset proxy
|
||||
require(
|
||||
assetMetadata.length >= 1,
|
||||
GT_ZERO_LENGTH_REQUIRED
|
||||
);
|
||||
uint8 assetProxyId = uint8(assetMetadata[0]);
|
||||
// Lookup assetProxy
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetMetadata, from, to, amount);
|
||||
assetProxy.transferFrom(assetData, from, to, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,6 @@ 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";
|
||||
@@ -30,9 +29,7 @@ import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
|
||||
contract MixinExchangeCore is
|
||||
SafeMath,
|
||||
LibMath,
|
||||
LibStatus,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
@@ -53,18 +50,26 @@ contract MixinExchangeCore is
|
||||
|
||||
////// Core exchange functions //////
|
||||
|
||||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
|
||||
/// @dev Cancels all orders created 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
|
||||
address makerAddress = getCurrentContextAddress();
|
||||
|
||||
// makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
|
||||
uint256 newMakerEpoch = salt + 1;
|
||||
uint256 oldMakerEpoch = makerEpoch[makerAddress];
|
||||
|
||||
// Ensure makerEpoch is monotonically increasing
|
||||
require(
|
||||
newMakerEpoch > makerEpoch[msg.sender], // epoch must be monotonically increasing
|
||||
newMakerEpoch > oldMakerEpoch,
|
||||
INVALID_NEW_MAKER_EPOCH
|
||||
);
|
||||
makerEpoch[msg.sender] = newMakerEpoch;
|
||||
emit CancelUpTo(msg.sender, newMakerEpoch);
|
||||
|
||||
// Update makerEpoch
|
||||
makerEpoch[makerAddress] = newMakerEpoch;
|
||||
emit CancelUpTo(makerAddress, newMakerEpoch);
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
@@ -86,32 +91,22 @@ contract MixinExchangeCore is
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Either our context is valid or we revert
|
||||
// Get amount of takerAsset to fill
|
||||
uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
|
||||
uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Validate context
|
||||
assertValidFill(
|
||||
order,
|
||||
orderInfo.orderStatus,
|
||||
orderInfo.orderHash,
|
||||
orderInfo,
|
||||
takerAddress,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
takerAssetFillAmount,
|
||||
takerAssetFilledAmount,
|
||||
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);
|
||||
fillResults = calculateFillResults(order, takerAssetFilledAmount);
|
||||
|
||||
// Update exchange internal state
|
||||
updateFilledState(
|
||||
@@ -121,37 +116,37 @@ contract MixinExchangeCore is
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, 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)
|
||||
/// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
|
||||
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);
|
||||
assertValidCancel(order, orderInfo);
|
||||
|
||||
// Perform cancel
|
||||
return updateCancelledState(order, orderInfo.orderStatus, orderInfo.orderHash);
|
||||
updateCancelledState(order, 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.
|
||||
/// See LibOrder.OrderInfo for a complete description.
|
||||
function getOrderInfo(Order memory order)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo memory orderInfo)
|
||||
returns (OrderInfo memory orderInfo)
|
||||
{
|
||||
// Compute the order hash
|
||||
orderInfo.orderHash = getOrderHash(order);
|
||||
@@ -161,7 +156,7 @@ contract MixinExchangeCore is
|
||||
// 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);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.INVALID_MAKER_ASSET_AMOUNT);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
@@ -170,169 +165,38 @@ contract MixinExchangeCore is
|
||||
// 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);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.INVALID_TAKER_ASSET_AMOUNT);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Validate order expiration
|
||||
if (block.timestamp >= order.expirationTimeSeconds) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_EXPIRED);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.EXPIRED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Check if order has been cancelled
|
||||
if (cancelled[orderInfo.orderHash]) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_CANCELLED);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
|
||||
return orderInfo;
|
||||
}
|
||||
if (makerEpoch[order.makerAddress] > order.salt) {
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_CANCELLED);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.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);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.FULLY_FILLED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// All other statuses are ruled out: order is Fillable
|
||||
orderInfo.orderStatus = uint8(Status.ORDER_FILLABLE);
|
||||
orderInfo.orderStatus = uint8(OrderStatus.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.
|
||||
@@ -365,72 +229,19 @@ contract MixinExchangeCore is
|
||||
);
|
||||
}
|
||||
|
||||
/// @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(
|
||||
@@ -440,7 +251,138 @@ contract MixinExchangeCore is
|
||||
order.makerAssetData,
|
||||
order.takerAssetData
|
||||
);
|
||||
}
|
||||
|
||||
return stateUpdated;
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo,
|
||||
address takerAddress,
|
||||
uint256 takerAssetFillAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// An order can only be filled if its status is FILLABLE.
|
||||
require(
|
||||
orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
|
||||
ORDER_UNFILLABLE
|
||||
);
|
||||
|
||||
// Revert if fill amount is invalid
|
||||
require(
|
||||
takerAssetFillAmount != 0,
|
||||
INVALID_TAKER_AMOUNT
|
||||
);
|
||||
|
||||
// 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_TAKER
|
||||
);
|
||||
}
|
||||
|
||||
// Validate Maker signature (check only if first time seen)
|
||||
if (orderInfo.orderTakerAssetFilledAmount == 0) {
|
||||
require(
|
||||
isValidSignature(orderInfo.orderHash, order.makerAddress, signature),
|
||||
INVALID_ORDER_SIGNATURE
|
||||
);
|
||||
}
|
||||
|
||||
// Validate fill order rounding
|
||||
require(
|
||||
!isRoundingError(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
),
|
||||
ROUNDING_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order to be cancelled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
function assertValidCancel(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// Ensure order is valid
|
||||
// An order can only be cancelled if its status is FILLABLE.
|
||||
require(
|
||||
orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
|
||||
ORDER_UNFILLABLE
|
||||
);
|
||||
|
||||
// Validate sender is allowed to cancel this order
|
||||
if (order.senderAddress != address(0)) {
|
||||
require(
|
||||
order.senderAddress == msg.sender,
|
||||
INVALID_SENDER
|
||||
);
|
||||
}
|
||||
|
||||
// Validate transaction signed by maker
|
||||
address makerAddress = getCurrentContextAddress();
|
||||
require(
|
||||
order.makerAddress == makerAddress,
|
||||
INVALID_MAKER
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
Order memory order,
|
||||
uint256 takerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (FillResults memory 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
|
||||
);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
}
|
||||
|
@@ -14,24 +14,17 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
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,
|
||||
@@ -50,17 +43,22 @@ contract MixinMatchOrders is
|
||||
/// @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,
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
returns (MatchedFillResults memory matchedFillResults)
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
|
||||
// If this assumption isn't true, the match will fail at signature validation.
|
||||
rightOrder.makerAssetData = leftOrder.takerAssetData;
|
||||
rightOrder.takerAssetData = leftOrder.makerAssetData;
|
||||
|
||||
// Get left & right order info
|
||||
OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
|
||||
OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
|
||||
LibOrder.OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
|
||||
LibOrder.OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
@@ -72,8 +70,6 @@ contract MixinMatchOrders is
|
||||
matchedFillResults = calculateMatchedFillResults(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
leftOrderInfo.orderStatus,
|
||||
rightOrderInfo.orderStatus,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount
|
||||
);
|
||||
@@ -81,31 +77,21 @@ contract MixinMatchOrders is
|
||||
// Validate fill contexts
|
||||
assertValidFill(
|
||||
leftOrder,
|
||||
leftOrderInfo.orderStatus,
|
||||
leftOrderInfo.orderHash,
|
||||
leftOrderInfo,
|
||||
takerAddress,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
leftSignature
|
||||
);
|
||||
assertValidFill(
|
||||
rightOrder,
|
||||
rightOrderInfo.orderStatus,
|
||||
rightOrderInfo.orderHash,
|
||||
rightOrderInfo,
|
||||
takerAddress,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
rightSignature
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
// Update exchange state
|
||||
updateFilledState(
|
||||
leftOrder,
|
||||
@@ -121,6 +107,14 @@ contract MixinMatchOrders is
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
return matchedFillResults;
|
||||
}
|
||||
@@ -129,25 +123,12 @@ contract MixinMatchOrders is
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function assertValidMatch(
|
||||
Order memory leftOrder,
|
||||
Order memory rightOrder
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
// 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).
|
||||
@@ -159,39 +140,7 @@ contract MixinMatchOrders is
|
||||
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
|
||||
NEGATIVE_SPREAD_REQUIRED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -201,21 +150,18 @@ contract MixinMatchOrders is
|
||||
/// 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 leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount 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
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
returns (MatchedFillResults memory matchedFillResults)
|
||||
pure
|
||||
returns (LibFillResults.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.
|
||||
@@ -226,71 +172,55 @@ contract MixinMatchOrders is
|
||||
// <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;
|
||||
uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
|
||||
uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
|
||||
uint256 leftTakerAssetFilledAmount;
|
||||
uint256 rightTakerAssetFilledAmount;
|
||||
if (
|
||||
safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
|
||||
safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
|
||||
) {
|
||||
// Left order will be fully filled: maximally fill left
|
||||
leftOrderAmountToFill = leftTakerAssetAmountRemaining;
|
||||
leftTakerAssetFilledAmount = 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(
|
||||
rightTakerAssetFilledAmount = getPartialAmount(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
leftOrderAmountToFill
|
||||
leftTakerAssetFilledAmount
|
||||
);
|
||||
} else {
|
||||
// Right order will be fully filled: maximally fill right
|
||||
rightOrderAmountToFill = rightTakerAssetAmountRemaining;
|
||||
rightTakerAssetFilledAmount = 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(
|
||||
leftTakerAssetFilledAmount = getPartialAmount(
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrderAmountToFill
|
||||
rightTakerAssetFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate fill results for left order
|
||||
uint8 status;
|
||||
(status, matchedFillResults.left) = calculateFillResults(
|
||||
matchedFillResults.left = calculateFillResults(
|
||||
leftOrder,
|
||||
leftOrderStatus,
|
||||
leftOrderFilledAmount,
|
||||
leftOrderAmountToFill
|
||||
);
|
||||
require(
|
||||
status == uint8(Status.SUCCESS),
|
||||
FAILED_TO_CALCULATE_FILL_RESULTS_FOR_LEFT_ORDER
|
||||
leftTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate fill results for right order
|
||||
(status, matchedFillResults.right) = calculateFillResults(
|
||||
matchedFillResults.right = calculateFillResults(
|
||||
rightOrder,
|
||||
rightOrderStatus,
|
||||
rightOrderFilledAmount,
|
||||
rightOrderAmountToFill
|
||||
);
|
||||
require(
|
||||
status == uint8(Status.SUCCESS),
|
||||
FAILED_TO_CALCULATE_FILL_RESULTS_FOR_RIGHT_ORDER
|
||||
rightTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate amount given to taker
|
||||
matchedFillResults.takerFillAmount = safeSub(
|
||||
matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Validate the fill results
|
||||
assertValidMatchResults(matchedFillResults);
|
||||
|
||||
// Return fill results
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
@@ -19,43 +19,36 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MMatchOrders.sol";
|
||||
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
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MMatchOrders,
|
||||
MSettlement,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// ZRX metadata used for fee transfers.
|
||||
// ZRX address encoded as a byte array.
|
||||
// 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;
|
||||
bytes internal ZRX_ASSET_DATA;
|
||||
uint8 constant ZRX_PROXY_ID = 1;
|
||||
|
||||
/// @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.
|
||||
/// TODO: _zrxAssetData 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)
|
||||
/// @param _zrxAssetData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
{
|
||||
ZRX_PROXY_DATA = _zrxProxyData;
|
||||
ZRX_ASSET_DATA = _zrxAssetData;
|
||||
}
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
@@ -65,30 +58,37 @@ contract MixinSettlement is
|
||||
function settleOrder(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
FillResults memory fillResults
|
||||
LibFillResults.FillResults memory fillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 makerAssetProxyId = uint8(popLastByte(order.makerAssetData));
|
||||
uint8 takerAssetProxyId = uint8(popLastByte(order.takerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
dispatchTransferFrom(
|
||||
order.makerAssetData,
|
||||
makerAssetProxyId,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
fillResults.makerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
order.takerAssetData,
|
||||
takerAssetProxyId,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
fillResults.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.takerFeePaid
|
||||
@@ -104,39 +104,47 @@ contract MixinSettlement is
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
address takerAddress,
|
||||
MatchedFillResults memory matchedFillResults
|
||||
LibFillResults.MatchedFillResults memory matchedFillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 leftMakerAssetProxyId = uint8(popLastByte(leftOrder.makerAssetData));
|
||||
uint8 rightMakerAssetProxyId = uint8(popLastByte(rightOrder.makerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
// Order makers and taker
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftMakerAssetProxyId,
|
||||
leftOrder.makerAddress,
|
||||
rightOrder.makerAddress,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
rightOrder.makerAssetData,
|
||||
rightMakerAssetProxyId,
|
||||
rightOrder.makerAddress,
|
||||
leftOrder.makerAddress,
|
||||
matchedFillResults.left.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftMakerAssetProxyId,
|
||||
leftOrder.makerAddress,
|
||||
takerAddress,
|
||||
matchedFillResults.takerFillAmount
|
||||
matchedFillResults.leftMakerAssetSpreadAmount
|
||||
);
|
||||
|
||||
// Maker fees
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
leftOrder.makerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
rightOrder.makerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.makerFeePaid
|
||||
@@ -145,7 +153,8 @@ contract MixinSettlement is
|
||||
// Taker fees
|
||||
if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
safeAdd(
|
||||
@@ -155,13 +164,15 @@ contract MixinSettlement is
|
||||
);
|
||||
} else {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.takerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
|
@@ -18,19 +18,28 @@
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./interfaces/ISigner.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "./interfaces/IWallet.sol";
|
||||
import "./interfaces/IValidator.sol";
|
||||
|
||||
contract MixinSignatureValidator is
|
||||
LibBytes,
|
||||
LibExchangeErrors,
|
||||
MSignatureValidator
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
// Personal message headers
|
||||
string constant ETH_PERSONAL_MESSAGE = "\x19Ethereum Signed Message:\n32";
|
||||
string constant TREZOR_PERSONAL_MESSAGE = "\x19Ethereum Signed Message:\n\x41";
|
||||
|
||||
// Mapping of hash => signer => signed
|
||||
mapping(bytes32 => mapping(address => bool)) preSigned;
|
||||
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.
|
||||
@@ -39,16 +48,30 @@ contract MixinSignatureValidator is
|
||||
function preSign(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature)
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
{
|
||||
require(
|
||||
isValidSignature(hash, signer, signature),
|
||||
SIGNATURE_VALIDATION_FAILED
|
||||
INVALID_SIGNATURE
|
||||
);
|
||||
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.
|
||||
@@ -57,47 +80,79 @@ contract MixinSignatureValidator is
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes memory signature)
|
||||
internal
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
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
|
||||
signature.length > 0,
|
||||
LENGTH_GREATER_THAN_0_REQUIRED
|
||||
);
|
||||
SignatureType signatureType = SignatureType(uint8(signature[0]));
|
||||
|
||||
// Variables are not scoped in Solidity
|
||||
// Pop last byte off of signature byte array.
|
||||
SignatureType signatureType = SignatureType(uint8(popLastByte(signature)));
|
||||
|
||||
// Variables are not scoped in Solidity.
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
address recovered;
|
||||
|
||||
// Always illegal signature
|
||||
// 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) {
|
||||
// NOTE: Reason cannot be assigned to a variable because of https://github.com/ethereum/solidity/issues/4051
|
||||
revert("Illegal signature type.");
|
||||
revert(SIGNATURE_ILLEGAL);
|
||||
|
||||
// Always invalid signature
|
||||
// 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 == 1,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
signature.length == 0,
|
||||
LENGTH_0_REQUIRED
|
||||
);
|
||||
isValid = false;
|
||||
return isValid;
|
||||
|
||||
// Implicitly signed by caller
|
||||
// Signature using EIP712
|
||||
} else if (signatureType == SignatureType.EIP712) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
LENGTH_65_REQUIRED
|
||||
);
|
||||
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,
|
||||
LENGTH_65_REQUIRED
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(
|
||||
keccak256(abi.encodePacked(ETH_PERSONAL_MESSAGE, 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
|
||||
@@ -107,44 +162,45 @@ contract MixinSignatureValidator is
|
||||
// submit using `Caller`. Having `Caller` allows this flexibility.
|
||||
} else if (signatureType == SignatureType.Caller) {
|
||||
require(
|
||||
signature.length == 1,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
signature.length == 0,
|
||||
LENGTH_0_REQUIRED
|
||||
);
|
||||
isValid = signer == msg.sender;
|
||||
return isValid;
|
||||
|
||||
// Signed using web3.eth_sign
|
||||
} else if (signatureType == SignatureType.Ecrecover) {
|
||||
require(
|
||||
signature.length == 66,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
);
|
||||
v = uint8(signature[1]);
|
||||
r = readBytes32(signature, 2);
|
||||
s = readBytes32(signature, 34);
|
||||
recovered = ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n32", hash),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
isValid = signer == recovered;
|
||||
// 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 using EIP712
|
||||
} else if (signatureType == SignatureType.EIP712) {
|
||||
require(
|
||||
signature.length == 66,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
// 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 = popLast20Bytes(signature);
|
||||
// Ensure signer has approved validator.
|
||||
if (!allowedValidators[signer][validator]) {
|
||||
return false;
|
||||
}
|
||||
isValid = IValidator(validator).isValidSignature(
|
||||
hash,
|
||||
signer,
|
||||
signature
|
||||
);
|
||||
v = uint8(signature[1]);
|
||||
r = readBytes32(signature, 2);
|
||||
s = readBytes32(signature, 34);
|
||||
recovered = ecrecover(hash, v, r, s);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Signature from Trezor hardware wallet
|
||||
// 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).
|
||||
@@ -154,14 +210,14 @@ contract MixinSignatureValidator is
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36
|
||||
} else if (signatureType == SignatureType.Trezor) {
|
||||
require(
|
||||
signature.length == 66,
|
||||
INVALID_SIGNATURE_LENGTH
|
||||
signature.length == 65,
|
||||
LENGTH_65_REQUIRED
|
||||
);
|
||||
v = uint8(signature[1]);
|
||||
r = readBytes32(signature, 2);
|
||||
s = readBytes32(signature, 34);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n\x41", hash),
|
||||
keccak256(abi.encodePacked(TREZOR_PERSONAL_MESSAGE, hash)),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
@@ -169,11 +225,6 @@ contract MixinSignatureValidator is
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Signature verified by signer contract
|
||||
} else if (signatureType == SignatureType.Contract) {
|
||||
isValid = ISigner(signer).isValidSignature(hash, signature);
|
||||
return isValid;
|
||||
|
||||
// Signer signed hash previously using the preSign function
|
||||
} else if (signatureType == SignatureType.PreSigned) {
|
||||
isValid = preSigned[hash][signer];
|
||||
@@ -185,7 +236,6 @@ contract MixinSignatureValidator is
|
||||
// that we currently support. In this case returning false
|
||||
// may lead the caller to incorrectly believe that the
|
||||
// signature was invalid.)
|
||||
// NOTE: Reason cannot be assigned to a variable because of https://github.com/ethereum/solidity/issues/4051
|
||||
revert("Unsupported signature type.");
|
||||
revert(SIGNATURE_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
|
||||
contract MixinTransactions is
|
||||
LibExchangeErrors,
|
||||
@@ -43,31 +43,36 @@ contract MixinTransactions is
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature)
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
{
|
||||
// Prevent reentrancy
|
||||
require(currentContextAddress == address(0));
|
||||
require(
|
||||
currentContextAddress == address(0),
|
||||
REENTRANCY_ILLEGAL
|
||||
);
|
||||
|
||||
// Calculate transaction hash
|
||||
bytes32 transactionHash = keccak256(
|
||||
bytes32 transactionHash = keccak256(abi.encodePacked(
|
||||
address(this),
|
||||
signer,
|
||||
salt,
|
||||
data
|
||||
);
|
||||
));
|
||||
|
||||
// Validate transaction has not been executed
|
||||
require(
|
||||
!transactions[transactionHash],
|
||||
DUPLICATE_TRANSACTION_HASH
|
||||
INVALID_TX_HASH
|
||||
);
|
||||
|
||||
// TODO: is SignatureType.Caller necessary if we make this check?
|
||||
// Transaction always valid if signer is sender of transaction
|
||||
if (signer != msg.sender) {
|
||||
// Validate signature
|
||||
require(
|
||||
isValidSignature(transactionHash, signer, signature),
|
||||
SIGNATURE_VALIDATION_FAILED
|
||||
INVALID_TX_SIGNATURE
|
||||
);
|
||||
|
||||
// Set the current transaction signer
|
||||
@@ -78,7 +83,7 @@ contract MixinTransactions is
|
||||
transactions[transactionHash] = true;
|
||||
require(
|
||||
address(this).delegatecall(data),
|
||||
TRANSACTION_EXECUTION_FAILED
|
||||
FAILED_EXECUTION
|
||||
);
|
||||
|
||||
// Reset current transaction signer
|
||||
|
@@ -19,18 +19,14 @@
|
||||
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";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
|
||||
contract MixinWrapperFunctions is
|
||||
SafeMath,
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore
|
||||
@@ -40,9 +36,10 @@ contract MixinWrapperFunctions is
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrder(
|
||||
Order memory order,
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
@@ -65,9 +62,10 @@ contract MixinWrapperFunctions is
|
||||
/// @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,
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
@@ -93,12 +91,12 @@ contract MixinWrapperFunctions is
|
||||
// | | 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 |
|
||||
// | | 0x140 | | 11. Offset to makerAssetData (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetData (*) |
|
||||
// | | 0x180 | 32 | makerAssetData Length |
|
||||
// | | 0x1A0 | ** | makerAssetData Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetData Length |
|
||||
// | | 0x1E0 | ** | takerAssetData Contents |
|
||||
// | | 0x200 | 32 | signature Length |
|
||||
// | | 0x220 | ** | signature Contents |
|
||||
|
||||
@@ -165,43 +163,45 @@ contract MixinWrapperFunctions is
|
||||
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
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
|
||||
dataAreaEnd := add(dataAreaEnd, 0x180)
|
||||
sourceOffset := add(sourceOffset, 0x180)
|
||||
|
||||
// Write offset to <order.makerAssetProxyMetadata>
|
||||
// Write offset to <order.makerAssetData>
|
||||
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.makerAssetProxyMetadata>
|
||||
// Calculate length of <order.makerAssetData>
|
||||
sourceOffset := mload(add(order, 0x140)) // makerAssetData
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.makerAssetProxyMetadata>
|
||||
// Write length of <order.makerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.makerAssetProxyMetadata>
|
||||
// Write contents of <order.makerAssetData>
|
||||
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>
|
||||
// Write offset to <order.takerAssetData>
|
||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.takerAssetProxyMetadata>
|
||||
// Calculate length of <order.takerAssetData>
|
||||
sourceOffset := mload(add(order, 0x160)) // takerAssetData
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.takerAssetProxyMetadata>
|
||||
// Write length of <order.takerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.takerAssetProxyMetadata>
|
||||
// Write contents of <order.takerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
@@ -263,38 +263,50 @@ contract MixinWrapperFunctions is
|
||||
/// @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.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
/// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
|
||||
function batchFillOrders(
|
||||
Order[] memory orders,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
fillOrder(
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @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.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
/// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
|
||||
function batchFillOrKillOrders(
|
||||
Order[] memory orders,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
fillOrKillOrder(
|
||||
FillResults memory singleFillResults = fillOrKillOrder(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
@@ -302,19 +314,25 @@ contract MixinWrapperFunctions is
|
||||
/// @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.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
/// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
|
||||
function batchFillOrdersNoThrow(
|
||||
Order[] memory orders,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
fillOrderNoThrow(
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
@@ -323,20 +341,20 @@ contract MixinWrapperFunctions is
|
||||
/// @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,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
|
||||
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
|
||||
);
|
||||
// We assume that asset being sold by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
|
||||
orders[i].takerAssetData = takerAssetData;
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
@@ -348,6 +366,14 @@ contract MixinWrapperFunctions is
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// HACK: the proxyId is "popped" from the byte array before a fill is settled
|
||||
// by subtracting from the length of the array. Since the popped byte is
|
||||
// still in memory, we can "unpop" it by incrementing the length of the byte array.
|
||||
assembly {
|
||||
let len := mload(takerAssetData)
|
||||
mstore(takerAssetData, add(len, 1))
|
||||
}
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
@@ -366,20 +392,20 @@ contract MixinWrapperFunctions is
|
||||
/// @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,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
|
||||
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
|
||||
);
|
||||
// We assume that asset being sold by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
|
||||
orders[i].takerAssetData = takerAssetData;
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
@@ -408,20 +434,20 @@ contract MixinWrapperFunctions is
|
||||
/// @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,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
|
||||
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
|
||||
);
|
||||
// We assume that asset being bought by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
|
||||
orders[i].makerAssetData = makerAssetData;
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
@@ -441,6 +467,14 @@ contract MixinWrapperFunctions is
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// HACK: the proxyId is "popped" from the byte array before a fill is settled
|
||||
// by subtracting from the length of the array. Since the popped byte is
|
||||
// still in memory, we can "unpop" it by incrementing the length of the byte array.
|
||||
assembly {
|
||||
let len := mload(makerAssetData)
|
||||
mstore(makerAssetData, add(len, 1))
|
||||
}
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
@@ -459,20 +493,20 @@ contract MixinWrapperFunctions is
|
||||
/// @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,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
|
||||
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
|
||||
);
|
||||
// We assume that asset being bought by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
|
||||
orders[i].makerAssetData = makerAssetData;
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
@@ -505,7 +539,7 @@ contract MixinWrapperFunctions is
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orders Array of order specifications.
|
||||
function batchCancelOrders(Order[] memory orders)
|
||||
function batchCancelOrders(LibOrder.Order[] memory orders)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
@@ -28,7 +28,8 @@ contract IAssetProxyDispatcher {
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy)
|
||||
address oldAssetProxy
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
|
@@ -20,17 +20,15 @@ pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./IExchangeCore.sol";
|
||||
import "./IMatchOrders";
|
||||
import "./ISettlement";
|
||||
import "./ISignatureValidator";
|
||||
import "./ITransactions";
|
||||
import "./IAssetProxyDispatcher";
|
||||
import "./IWrapperFunctions";
|
||||
import "./IMatchOrders.sol";
|
||||
import "./ISignatureValidator.sol";
|
||||
import "./ITransactions.sol";
|
||||
import "./IAssetProxyDispatcher.sol";
|
||||
import "./IWrapperFunctions.sol";
|
||||
|
||||
contract IExchange is
|
||||
IExchangeCore,
|
||||
IMatchOrders,
|
||||
ISettlement,
|
||||
ISignatureValidator,
|
||||
ITransactions,
|
||||
IAssetProxyDispatcher,
|
||||
|
@@ -37,17 +37,15 @@ contract IExchangeCore {
|
||||
function fillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
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);
|
||||
public;
|
||||
|
||||
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||
/// @param order Order to gather information on.
|
||||
@@ -57,24 +55,4 @@ contract IExchangeCore {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
@@ -27,6 +27,30 @@ contract ISignatureValidator {
|
||||
function preSign(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature)
|
||||
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;
|
||||
|
||||
/// @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
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ contract ITransactions {
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature)
|
||||
bytes signature
|
||||
)
|
||||
external;
|
||||
}
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.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);
|
||||
}
|
@@ -18,7 +18,7 @@
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract ISigner {
|
||||
contract IWallet {
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
@@ -26,7 +26,8 @@ contract ISigner {
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
bytes signature)
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid);
|
@@ -19,27 +19,21 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IWrapperFunctions is
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore
|
||||
{
|
||||
contract IWrapperFunctions {
|
||||
/// @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.LibOrder.Order memory order,
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.LibFillResults.FillResults memory fillResults);
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
@@ -50,7 +44,8 @@ contract IWrapperFunctions is
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
@@ -58,32 +53,41 @@ contract IWrapperFunctions is
|
||||
/// @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.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public;
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @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.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public;
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @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.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
public;
|
||||
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.
|
||||
/// @param orders Array of order specifications.
|
||||
@@ -93,7 +97,8 @@ contract IWrapperFunctions is
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -106,7 +111,8 @@ contract IWrapperFunctions is
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -118,7 +124,8 @@ contract IWrapperFunctions is
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -131,7 +138,8 @@ contract IWrapperFunctions is
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
|
@@ -19,42 +19,43 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract LibExchangeErrors {
|
||||
/// Order validation errors ///
|
||||
string constant ORDER_UNFILLABLE = "ORDER_UNFILLABLE"; // Order cannot be filled.
|
||||
string constant INVALID_MAKER = "INVALID_MAKER"; // Invalid makerAddress.
|
||||
string constant INVALID_TAKER = "INVALID_TAKER"; // Invalid takerAddress.
|
||||
string constant INVALID_SENDER = "INVALID_SENDER"; // Invalid `msg.sender`.
|
||||
string constant INVALID_ORDER_SIGNATURE = "INVALID_ORDER_SIGNATURE"; // Signature validation failed.
|
||||
|
||||
/// fillOrder validation errors ///
|
||||
string constant INVALID_TAKER_AMOUNT = "INVALID_TAKER_AMOUNT"; // takerAssetFillAmount cannot equal 0.
|
||||
string constant ROUNDING_ERROR = "ROUNDING_ERROR"; // Rounding error greater than 0.1% of takerAssetFillAmount.
|
||||
|
||||
/// Signature validation errors ///
|
||||
string constant INVALID_SIGNATURE = "INVALID_SIGNATURE"; // Signature validation failed.
|
||||
string constant SIGNATURE_ILLEGAL = "SIGNATURE_ILLEGAL"; // Signature type is illegal.
|
||||
string constant SIGNATURE_UNSUPPORTED = "SIGNATURE_UNSUPPORTED"; // Signature type unsupported.
|
||||
|
||||
/// cancelOrdersUptTo errors ///
|
||||
string constant INVALID_NEW_MAKER_EPOCH = "INVALID_NEW_MAKER_EPOCH"; // Specified salt must be greater than or equal to existing makerEpoch.
|
||||
|
||||
// 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.";
|
||||
/// fillOrKillOrder errors ///
|
||||
string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired takerAssetFillAmount could not be completely filled.
|
||||
|
||||
// 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.";
|
||||
/// matchOrders errors ///
|
||||
string constant NEGATIVE_SPREAD_REQUIRED = "NEGATIVE_SPREAD_REQUIRED"; // Matched orders must have a negative spread.
|
||||
|
||||
// Transaction revert reasons
|
||||
string constant DUPLICATE_TRANSACTION_HASH = "Transaction has already been executed.";
|
||||
string constant TRANSACTION_EXECUTION_FAILED = "Transaction execution failed.";
|
||||
/// Transaction errors ///
|
||||
string constant REENTRANCY_ILLEGAL = "REENTRANCY_ILLEGAL"; // Recursive reentrancy is not allowed.
|
||||
string constant INVALID_TX_HASH = "INVALID_TX_HASH"; // Transaction has already been executed.
|
||||
string constant INVALID_TX_SIGNATURE = "INVALID_TX_SIGNATURE"; // Signature validation failed.
|
||||
string constant FAILED_EXECUTION = "FAILED_EXECUTION"; // Transaction execution failed.
|
||||
|
||||
/// registerAssetProxy errors ///
|
||||
string constant ASSET_PROXY_MISMATCH = "ASSET_PROXY_MISMATCH"; // oldAssetProxy proxy does not match currentAssetProxy.
|
||||
string constant ASSET_PROXY_ID_MISMATCH = "ASSET_PROXY_ID_MISMATCH"; // newAssetProxyId does not match given assetProxyId.
|
||||
|
||||
// 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.";
|
||||
/// Length validation errors ///
|
||||
string constant LENGTH_GREATER_THAN_0_REQUIRED = "LENGTH_GREATER_THAN_0_REQUIRED"; // Byte array must have a length greater than 0.
|
||||
string constant LENGTH_0_REQUIRED = "LENGTH_1_REQUIRED"; // Byte array must have a length of 1.
|
||||
string constant LENGTH_65_REQUIRED = "LENGTH_66_REQUIRED"; // Byte array must have a length of 66.
|
||||
}
|
||||
|
@@ -32,9 +32,9 @@ contract LibFillResults is
|
||||
}
|
||||
|
||||
struct MatchedFillResults {
|
||||
LibFillResults.FillResults left;
|
||||
LibFillResults.FillResults right;
|
||||
uint256 takerFillAmount;
|
||||
FillResults left;
|
||||
FillResults right;
|
||||
uint256 leftMakerAssetSpreadAmount;
|
||||
}
|
||||
|
||||
/// @dev Adds properties of both FillResults instances.
|
||||
@@ -50,19 +50,4 @@ contract LibFillResults is
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -45,26 +45,6 @@ contract LibMath is
|
||||
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.
|
||||
|
@@ -20,11 +20,11 @@ pragma solidity ^0.4.24;
|
||||
|
||||
contract LibOrder {
|
||||
|
||||
bytes32 constant DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(
|
||||
bytes32 constant DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
|
||||
"DomainSeparator(address contract)"
|
||||
);
|
||||
));
|
||||
|
||||
bytes32 constant ORDER_SCHEMA_HASH = keccak256(
|
||||
bytes32 constant ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(
|
||||
"Order(",
|
||||
"address makerAddress,",
|
||||
"address takerAddress,",
|
||||
@@ -39,7 +39,19 @@ contract LibOrder {
|
||||
"bytes makerAssetData,",
|
||||
"bytes takerAssetData,",
|
||||
")"
|
||||
);
|
||||
));
|
||||
|
||||
// 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.
|
||||
enum OrderStatus {
|
||||
INVALID, // Default value
|
||||
INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
|
||||
INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
|
||||
FILLABLE, // Order is fillable
|
||||
EXPIRED, // Order has already expired
|
||||
FULLY_FILLED, // Order is fully filled
|
||||
CANCELLED // Order has been cancelled
|
||||
}
|
||||
|
||||
struct Order {
|
||||
address makerAddress;
|
||||
@@ -75,11 +87,11 @@ contract LibOrder {
|
||||
{
|
||||
// TODO: EIP712 is not finalized yet
|
||||
// Source: https://github.com/ethereum/EIPs/pull/712
|
||||
orderHash = keccak256(
|
||||
orderHash = keccak256(abi.encodePacked(
|
||||
DOMAIN_SEPARATOR_SCHEMA_HASH,
|
||||
keccak256(address(this)),
|
||||
keccak256(abi.encodePacked(address(this))),
|
||||
ORDER_SCHEMA_HASH,
|
||||
keccak256(
|
||||
keccak256(abi.encodePacked(
|
||||
order.makerAddress,
|
||||
order.takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
@@ -90,10 +102,10 @@ contract LibOrder {
|
||||
order.takerFee,
|
||||
order.expirationTimeSeconds,
|
||||
order.salt,
|
||||
keccak256(order.makerAssetData),
|
||||
keccak256(order.takerAssetData)
|
||||
)
|
||||
);
|
||||
keccak256(abi.encodePacked(order.makerAssetData)),
|
||||
keccak256(abi.encodePacked(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);
|
||||
}
|
@@ -33,14 +33,17 @@ contract MAssetProxyDispatcher is
|
||||
);
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param assetProxyId Id of assetProxy to dispach to.
|
||||
/// @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,
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
||||
|
@@ -26,7 +26,6 @@ import "../interfaces/IExchangeCore.sol";
|
||||
contract MExchangeCore is
|
||||
IExchangeCore
|
||||
{
|
||||
|
||||
// Fill event is emitted whenever an order is filled.
|
||||
event Fill(
|
||||
address indexed makerAddress,
|
||||
@@ -56,25 +55,6 @@ contract MExchangeCore is
|
||||
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.
|
||||
@@ -89,29 +69,55 @@ contract MExchangeCore is
|
||||
)
|
||||
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;
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo Status, orderHash, and amount already filled of order.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
address takerAddress,
|
||||
uint256 takerAssetFillAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (bool stateUpdated);
|
||||
view;
|
||||
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order to be cancelled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
function assertValidCancel(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo
|
||||
)
|
||||
internal
|
||||
view;
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
import "./MExchangeCore.sol";
|
||||
import "../interfaces/IMatchOrders.sol";
|
||||
|
||||
contract MMatchOrders is
|
||||
@@ -34,12 +33,8 @@ contract MMatchOrders is
|
||||
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;
|
||||
internal
|
||||
pure;
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
@@ -47,19 +42,16 @@ contract MMatchOrders is
|
||||
/// 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 leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount 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
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "./MMatchOrders.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract MSettlement {
|
||||
|
@@ -25,26 +25,14 @@ contract MSignatureValidator is
|
||||
{
|
||||
// Allowed signature types.
|
||||
enum SignatureType {
|
||||
Illegal, // Default value
|
||||
Invalid,
|
||||
Caller,
|
||||
Ecrecover,
|
||||
EIP712,
|
||||
Trezor,
|
||||
Contract,
|
||||
PreSigned
|
||||
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);
|
||||
}
|
||||
|
@@ -31,7 +31,8 @@ contract DummyERC20Token is Mintable, Ownable {
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint256 _decimals,
|
||||
uint256 _totalSupply)
|
||||
uint256 _totalSupply
|
||||
)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Smart Contract Solutions, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../../tokens/ERC721Token/IERC721Receiver.sol";
|
||||
|
||||
contract DummyERC721Receiver is
|
||||
IERC721Receiver
|
||||
{
|
||||
|
||||
event TokenReceived(
|
||||
address from,
|
||||
uint256 tokenId,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/**
|
||||
* @notice Handle the receipt of an NFT
|
||||
* @dev The ERC721 smart contract calls this function on the recipient
|
||||
* after a `safetransfer`. This function MAY throw to revert and reject the
|
||||
* transfer. This function MUST use 50,000 gas or less. Return of other
|
||||
* than the magic value MUST result in the transaction being reverted.
|
||||
* Note: the contract address is always the message sender.
|
||||
* @param _from The sending address
|
||||
* @param _tokenId The NFT identifier which is being transfered
|
||||
* @param _data Additional data with no specified format
|
||||
* @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
|
||||
*/
|
||||
function onERC721Received(
|
||||
address _from,
|
||||
uint256 _tokenId,
|
||||
bytes _data
|
||||
)
|
||||
public
|
||||
returns (bytes4)
|
||||
{
|
||||
emit TokenReceived(_from, _tokenId, _data);
|
||||
return ERC721_RECEIVED;
|
||||
}
|
||||
}
|
@@ -34,7 +34,8 @@ contract DummyERC721Token is
|
||||
*/
|
||||
constructor (
|
||||
string name,
|
||||
string symbol)
|
||||
string symbol
|
||||
)
|
||||
public
|
||||
ERC721Token(name, symbol)
|
||||
{}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../protocol/AssetProxy/ERC20Proxy.sol";
|
||||
import "../../protocol/AssetProxy/ERC721Proxy.sol";
|
||||
|
||||
contract TestAssetDataDecoders is
|
||||
ERC721Proxy
|
||||
{
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function publicDecodeERC721Data(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
(
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
return (
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
@@ -23,12 +23,13 @@ import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
|
||||
|
||||
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
|
||||
function publicDispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
{
|
||||
dispatchTransferFrom(assetMetadata, from, to, amount);
|
||||
dispatchTransferFrom(assetData, assetProxyId, from, to, amount);
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,30 @@ 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 publicPopLastByte(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory, bytes1 result)
|
||||
{
|
||||
result = popLastByte(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 publicPopLast20Bytes(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory, address result)
|
||||
{
|
||||
result = popLast20Bytes(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.
|
||||
@@ -38,13 +62,29 @@ contract TestLibBytes is
|
||||
return equal;
|
||||
}
|
||||
|
||||
/// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
|
||||
/// @param dest Byte array that will be overwritten with source bytes.
|
||||
/// @param source Byte array to copy onto dest bytes.
|
||||
function publicDeepCopyBytes(
|
||||
bytes memory dest,
|
||||
bytes memory source
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
deepCopyBytes(dest, source);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/// @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)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (address result)
|
||||
@@ -60,7 +100,8 @@ contract TestLibBytes is
|
||||
function publicWriteAddress(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
address input)
|
||||
address input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -75,7 +116,8 @@ contract TestLibBytes is
|
||||
/// @return bytes32 value from byte array.
|
||||
function publicReadBytes32(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
@@ -91,7 +133,8 @@ contract TestLibBytes is
|
||||
function publicWriteBytes32(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes32 input)
|
||||
bytes32 input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -106,7 +149,8 @@ contract TestLibBytes is
|
||||
/// @return uint256 value from byte array.
|
||||
function publicReadUint256(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 result)
|
||||
@@ -122,7 +166,8 @@ contract TestLibBytes is
|
||||
function publicWriteUint256(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
uint256 input)
|
||||
uint256 input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -142,4 +187,38 @@ contract TestLibBytes is
|
||||
result = readFirst4(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Reads nested bytes from a specific position.
|
||||
/// @param b Byte array containing nested bytes.
|
||||
/// @param index Index of nested bytes.
|
||||
/// @return result Nested bytes.
|
||||
function publicReadBytes(
|
||||
bytes memory b,
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory result)
|
||||
{
|
||||
result = readBytes(b, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Inserts bytes at 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 bytes to insert.
|
||||
/// @return b Updated input byte array
|
||||
function publicWriteBytes(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes memory input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
writeBytes(b, index, input);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user