Compare commits
533 Commits
@0x/react-
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
b6b618e5ce | ||
|
0bb8887027 | ||
|
fabfdd0aa2 | ||
|
8f8336b344 | ||
|
d10659f986 | ||
|
e853555165 | ||
|
2ce09d73ac | ||
|
14f48a5f4f | ||
|
8da4e4a830 | ||
|
88ae8311c8 | ||
|
eabf6a466a | ||
|
989f691d06 | ||
|
52a3dae7cb | ||
|
8a6dfacf71 | ||
|
19ca6c13ad | ||
|
9196f122dd | ||
|
55e3d81c58 | ||
|
80caa16718 | ||
|
ddc5aaacdb | ||
|
38825865cc | ||
|
157b2efa1d | ||
|
212a2d229a | ||
|
ccb89fb26a | ||
|
3a0b0c0973 | ||
|
c159ed9ebb | ||
|
e37dbcc273 | ||
|
841e660b1f | ||
|
391aba5f37 | ||
|
f5d30f4a07 | ||
|
230cf7dfb7 | ||
|
8734b70f83 | ||
|
ff9a2b2d9a | ||
|
a41dab2922 | ||
|
f4504106a1 | ||
|
1a5b8041c7 | ||
|
1e2170f8bb | ||
|
0a4a973a7f | ||
|
67137cadac | ||
|
ead4afa06b | ||
|
e39ef95191 | ||
|
3d7585671f | ||
|
44806106db | ||
|
6a8197a4e8 | ||
|
4d4b4e0f2b | ||
|
82da33d742 | ||
|
1c6130a492 | ||
|
dabe5e939f | ||
|
b4ac6d3439 | ||
|
d0ea74e180 | ||
|
a5f77f3964 | ||
|
9401bb53e8 | ||
|
347c6d02cf | ||
|
64a0080616 | ||
|
288a7d4cea | ||
|
1207b68f57 | ||
|
2b82187fe0 | ||
|
3e2dbfc83c | ||
|
6691f490bc | ||
|
a7db900e51 | ||
|
cfa2a90dae | ||
|
feebb45e9d | ||
|
13a2f3a330 | ||
|
1da8801084 | ||
|
7a7b17c4f3 | ||
|
2afb06de13 | ||
|
ac771e2865 | ||
|
4b09204936 | ||
|
e4a5518a7c | ||
|
e83507ba98 | ||
|
6e5b77edb2 | ||
|
98167da8fa | ||
|
11d5fec59b | ||
|
ed02f4ca88 | ||
|
e7c612971d | ||
|
242a2e21b5 | ||
|
92a1e5413b | ||
|
e1ab9aa690 | ||
|
222f7e6fd4 | ||
|
59001f827b | ||
|
549bfe98f1 | ||
|
64e3b6f5ee | ||
|
2fdc0426ff | ||
|
e6c70fda66 | ||
|
50da1354f3 | ||
|
e503cacf57 | ||
|
6a1e0edc78 | ||
|
048f5c2771 | ||
|
d9378e9a8f | ||
|
f77aaaf2e0 | ||
|
380835b151 | ||
|
857d91df85 | ||
|
cd9a6b0de7 | ||
|
86333f4928 | ||
|
d1975bd5dd | ||
|
08b9f27eac | ||
|
5b2cf8a776 | ||
|
7394106880 | ||
|
9134a7ae1e | ||
|
c617e9f483 | ||
|
545fcef716 | ||
|
e20fa3a1bf | ||
|
9d01b47d5b | ||
|
fa4c34df41 | ||
|
9f8ab4d626 | ||
|
1971c9cecd | ||
|
82f730831d | ||
|
035167e5b7 | ||
|
323fb0a965 | ||
|
45aacf122f | ||
|
5dcf7919fc | ||
|
f15560bd89 | ||
|
bf3ae730d6 | ||
|
92ce258bb4 | ||
|
5810e7df82 | ||
|
f2cbf4a561 | ||
|
0c8bb2e675 | ||
|
f51c4f9617 | ||
|
5345f7c983 | ||
|
7d9e43b2e1 | ||
|
570c1e1809 | ||
|
720d335b09 | ||
|
f0ecda1a48 | ||
|
4ed111a7d4 | ||
|
fc257523c7 | ||
|
9775f8d83c | ||
|
01a1b19556 | ||
|
bd228034fd | ||
|
2672a5c59f | ||
|
5f383430eb | ||
|
66ec3e9f4d | ||
|
c269c427a6 | ||
|
212855ebd8 | ||
|
8f78945a73 | ||
|
86d50cf597 | ||
|
8986d506a5 | ||
|
3d2c945c35 | ||
|
8206a3969f | ||
|
43afe67593 | ||
|
ecf939f8c8 | ||
|
f0c4ccfa1e | ||
|
718d48b7d5 | ||
|
d5e88677ae | ||
|
b1cfdc7a6a | ||
|
5c5f815b20 | ||
|
d9edb9675f | ||
|
be6fce5a89 | ||
|
12afeb30ae | ||
|
23df406ff0 | ||
|
c9ecef4fc3 | ||
|
62f0a867a8 | ||
|
f68b8d82e0 | ||
|
6b7cb13e9a | ||
|
613af6013a | ||
|
0db56a781e | ||
|
fe7674b184 | ||
|
44a6fe7310 | ||
|
46690f0c35 | ||
|
cfc4e345cc | ||
|
c68278d824 | ||
|
09600a71cd | ||
|
d66ba70f5e | ||
|
e7c4120d24 | ||
|
1212e534a8 | ||
|
899d0f1e42 | ||
|
dde4ed3754 | ||
|
b596e02752 | ||
|
d5afe696da | ||
|
976be66dee | ||
|
98c8a6387a | ||
|
be1b636e30 | ||
|
8bae0b81aa | ||
|
7ee19e1306 | ||
|
626d0dfa93 | ||
|
8453c616a5 | ||
|
56bc2944d0 | ||
|
b2cf701e30 | ||
|
9a3b29acb7 | ||
|
85b217f167 | ||
|
a7700d6c22 | ||
|
1e274518dd | ||
|
f4f8927c79 | ||
|
60b7890f16 | ||
|
4d46290ef6 | ||
|
00f7e2cfc3 | ||
|
e742708261 | ||
|
8c9de31c5c | ||
|
2bf992f0ac | ||
|
52a01bcc11 | ||
|
f250e03c40 | ||
|
75acbfb042 | ||
|
740fd6f5d9 | ||
|
c58306cd49 | ||
|
985696631c | ||
|
d8a3d7f920 | ||
|
b6b96f0eee | ||
|
3f037ef3cc | ||
|
5c2d3fb3da | ||
|
84d38ea878 | ||
|
6226aa0b23 | ||
|
72af35834b | ||
|
3019e3817f | ||
|
da9e90faf0 | ||
|
e737395c2b | ||
|
5a33167594 | ||
|
dfb7e50948 | ||
|
b43c9f075c | ||
|
f42ce6adb5 | ||
|
bf533bbdbb | ||
|
9328729c4c | ||
|
2e23a044ca | ||
|
691a3a1e72 | ||
|
fc40f9634b | ||
|
4969441f21 | ||
|
d04d50794e | ||
|
5e1fbe34a9 | ||
|
2b75829a0c | ||
|
3b3fd0a3a2 | ||
|
1e4b61008a | ||
|
ffb71e9fd5 | ||
|
c1aeb4bde6 | ||
|
66bca5cd81 | ||
|
b68df3a067 | ||
|
066f3bb646 | ||
|
661c334928 | ||
|
a1895d4157 | ||
|
1e7efe026a | ||
|
02e7da979a | ||
|
bd2839110b | ||
|
1bcb2697e7 | ||
|
fdb9a664f5 | ||
|
8099c334c7 | ||
|
344d28ab78 | ||
|
5e41168305 | ||
|
dd97669cdd | ||
|
af75581659 | ||
|
3c08f5b86a | ||
|
7809cad6cb | ||
|
3e59029966 | ||
|
24249bcb4d | ||
|
543011c3de | ||
|
4d9f2586d9 | ||
|
7f94ebe362 | ||
|
c9bf1eda54 | ||
|
2cd4d9004c | ||
|
35cd0319d4 | ||
|
899030e966 | ||
|
15e3944d23 | ||
|
f1fbaedb0f | ||
|
cf04062a19 | ||
|
2e922bf7db | ||
|
741a731ecb | ||
|
91bff1976c | ||
|
fad500042a | ||
|
bdb2a01385 | ||
|
f372cd2d13 | ||
|
a435da910f | ||
|
f1d96d9673 | ||
|
45226ee1f6 | ||
|
03b8d29740 | ||
|
80a4af249f | ||
|
900d444946 | ||
|
7ca9393d2d | ||
|
b22d7bb310 | ||
|
c742cdfe5c | ||
|
2d3fe02cd7 | ||
|
7d61cb6bac | ||
|
a804433a7a | ||
|
11082320c2 | ||
|
9f9797b123 | ||
|
05d34616b7 | ||
|
c7f474ada1 | ||
|
c7328a63d0 | ||
|
db818794d5 | ||
|
b4b34e4890 | ||
|
eec016380d | ||
|
dcab272be0 | ||
|
418d033a5c | ||
|
e7a7713b80 | ||
|
52a580d845 | ||
|
ea42a0b5f5 | ||
|
a0b63da9a6 | ||
|
8d9932fc42 | ||
|
54be45bedc | ||
|
3c9d2a562b | ||
|
654bd5175c | ||
|
9db660cd3f | ||
|
9aeadff9bd | ||
|
cd631b789b | ||
|
4d98408aaf | ||
|
490aafba4e | ||
|
3cd31d49bb | ||
|
6dd78b8d35 | ||
|
bd51c34098 | ||
|
0e758fadee | ||
|
a67659ff8e | ||
|
d1203f90da | ||
|
c5f6ebee18 | ||
|
41cc5234c4 | ||
|
c2d3e5f052 | ||
|
f944b95e32 | ||
|
0a5b919cd9 | ||
|
b5f85c11fe | ||
|
5d44b5e913 | ||
|
dd1961d86c | ||
|
f3539bf448 | ||
|
d831e559f0 | ||
|
cc079660f3 | ||
|
4460dac697 | ||
|
31190f921c | ||
|
22515d8dce | ||
|
a099d970a4 | ||
|
95bb2c5504 | ||
|
0b1262cc4d | ||
|
f9244f6f7e | ||
|
9dd4ea1584 | ||
|
9d085cdb61 | ||
|
f00a2dbc59 | ||
|
20862d47ab | ||
|
cfa1bf36de | ||
|
c362b33b5a | ||
|
222a151eff | ||
|
d6115cff25 | ||
|
6459522617 | ||
|
16e1f0eea1 | ||
|
0564ac1530 | ||
|
b896f82282 | ||
|
d737d419d9 | ||
|
0de2b6983b | ||
|
25628c34ee | ||
|
54fdccd397 | ||
|
27af4a988d | ||
|
fddad131a2 | ||
|
4d493eeebd | ||
|
14c1495a1a | ||
|
49c029ddb3 | ||
|
ddbe142c4c | ||
|
4710b40e45 | ||
|
be0b296769 | ||
|
0a0ee67740 | ||
|
943d648225 | ||
|
6d835f5cc1 | ||
|
a59cd67acf | ||
|
bbc06be091 | ||
|
d303e9f347 | ||
|
85ee923d89 | ||
|
fe6ba20ff5 | ||
|
18acf50b12 | ||
|
509fabb61c | ||
|
cc3378b4cd | ||
|
8d3ccf333d | ||
|
520919b165 | ||
|
600b86dd31 | ||
|
9c3fdd2584 | ||
|
73974cd90f | ||
|
8a60b3b402 | ||
|
59ed5ae6b7 | ||
|
c687385974 | ||
|
2f72e15ea7 | ||
|
7ea99baeb2 | ||
|
14f3d20772 | ||
|
72f51df25f | ||
|
a94b58e304 | ||
|
d327fabf9c | ||
|
9e02888c74 | ||
|
98c9a847f3 | ||
|
a159f4c9d6 | ||
|
b197731ed2 | ||
|
028f54fdf0 | ||
|
de62a0f8ed | ||
|
a0fcc50a5f | ||
|
4f186e843c | ||
|
df64c20587 | ||
|
c78a602990 | ||
|
0acec57ba9 | ||
|
7423028fea | ||
|
49d951b7be | ||
|
a554c9518d | ||
|
f3c7ba445e | ||
|
3abff41385 | ||
|
6c36832f0e | ||
|
310c18707b | ||
|
422a4a5578 | ||
|
a995b2e1ae | ||
|
90ad681a9e | ||
|
2ff5c39712 | ||
|
ded849fd6d | ||
|
02f7064953 | ||
|
1ddadfce1e | ||
|
7720e5007c | ||
|
ccfd021796 | ||
|
fdcad84cee | ||
|
ad3e3b8421 | ||
|
f67b4f8902 | ||
|
3c0d7319ba | ||
|
7f0aab6ec6 | ||
|
669578a926 | ||
|
fa1db64a8e | ||
|
7cf60fa927 | ||
|
75a0d3e494 | ||
|
a98218ae22 | ||
|
10952e9dc4 | ||
|
b36e23471b | ||
|
f45bf1c95b | ||
|
d4db2587aa | ||
|
62e6336a7d | ||
|
2d8acd4711 | ||
|
d7d95be042 | ||
|
e3c97f0681 | ||
|
1a4fa015b9 | ||
|
63dacfaac5 | ||
|
f7263ac2c6 | ||
|
c7d7e1f0e3 | ||
|
9c54b615f5 | ||
|
69fe1aa981 | ||
|
bfb3d19e3b | ||
|
0b4e62a63e | ||
|
5cdbc03e71 | ||
|
16cd6dd25d | ||
|
fc71e7f99f | ||
|
e740380731 | ||
|
f9921d2c91 | ||
|
d8bfc92cc5 | ||
|
1f2214f891 | ||
|
50835e317f | ||
|
6c8d4dcc1e | ||
|
85a7efbd61 | ||
|
6b5ef10467 | ||
|
0bf46bfcb5 | ||
|
8b8dc7ac78 | ||
|
a017122c44 | ||
|
86a9a892d2 | ||
|
f31a141d78 | ||
|
fa67997424 | ||
|
a5f06c577d | ||
|
e575672877 | ||
|
a34d5b29e8 | ||
|
91ec65da1b | ||
|
ee8d40a66e | ||
|
38ac2e80ed | ||
|
8b70762e34 | ||
|
18c613a611 | ||
|
957f8c56a1 | ||
|
b16446877e | ||
|
9164d58dc7 | ||
|
0beb2f9d3c | ||
|
ccdd66052a | ||
|
518fd814b6 | ||
|
f49bb78dba | ||
|
a54aa77d28 | ||
|
f85e443c9c | ||
|
399e004e7f | ||
|
3099ba71eb | ||
|
951fcf384c | ||
|
c750368a3e | ||
|
3149d86855 | ||
|
3aaf21e34e | ||
|
519c375a42 | ||
|
3ed2c732bd | ||
|
0aa5550d0f | ||
|
1bc8dd83d3 | ||
|
c642cd6fed | ||
|
f72918362d | ||
|
28c4ca73ab | ||
|
a256494ec8 | ||
|
5fd359a64f | ||
|
e043735362 | ||
|
7010b1adb9 | ||
|
17ff262729 | ||
|
1c18838cd8 | ||
|
55b87ae78d | ||
|
e446e902f3 | ||
|
095b52e0b2 | ||
|
4f25ff6a50 | ||
|
6242e0aeec | ||
|
fde9fc9dd4 | ||
|
c481e42673 | ||
|
5e228d7232 | ||
|
6b8e40fdc9 | ||
|
bca44bf9e3 | ||
|
08e49dcf2e | ||
|
50f5002b71 | ||
|
346c6fc590 | ||
|
3bdc1802cb | ||
|
095882d016 | ||
|
1693506f80 | ||
|
b88e42a52d | ||
|
8d1b27d130 | ||
|
1148d37102 | ||
|
88704ce417 | ||
|
9f69d2cb76 | ||
|
55fd71c5e1 | ||
|
1991bd437f | ||
|
1bff790628 | ||
|
0010ca3e03 | ||
|
9edb5dae88 | ||
|
85b49096dc | ||
|
a7eaa10220 | ||
|
5a46ce55b6 | ||
|
dbebbecab1 | ||
|
c7593e66bf | ||
|
d52dc69279 | ||
|
1c65fa212d | ||
|
be88eb00f8 | ||
|
65c60f5386 | ||
|
83a043e639 | ||
|
8175192f60 | ||
|
7d2c975d73 | ||
|
e5153737d8 | ||
|
88766a02c7 | ||
|
8162394797 | ||
|
fd001186dd | ||
|
128fef8838 | ||
|
1e25a0654a | ||
|
82b0ff6008 | ||
|
ca7c3630f9 | ||
|
260bb8218f | ||
|
a691de7d55 | ||
|
5674c484e2 | ||
|
9286dc284c | ||
|
624b71bd39 | ||
|
b7ea605a3b | ||
|
489a787de8 | ||
|
84150036ed | ||
|
619123720c | ||
|
cc98ff9fe6 | ||
|
39d159f38c | ||
|
ca8eb90cec | ||
|
f8e3e28d85 | ||
|
4d868489bd | ||
|
b06f09f6af | ||
|
bf00f5f945 | ||
|
6ceb6cc301 | ||
|
00a6afaa8e |
@@ -11,9 +11,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||||
|
- run:
|
||||||
|
# HACK(albrow): Without this, yarn commands will sometimes
|
||||||
|
# fail with a "permission denied" error.
|
||||||
|
name: Set npm path
|
||||||
|
command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc
|
||||||
- run:
|
- run:
|
||||||
name: install-yarn
|
name: install-yarn
|
||||||
command: sudo npm install --global yarn@1.9.4
|
command: npm install --global yarn@1.9.4
|
||||||
- run:
|
- run:
|
||||||
name: yarn
|
name: yarn
|
||||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||||
@@ -24,6 +29,10 @@ jobs:
|
|||||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- ~/repo
|
- ~/repo
|
||||||
|
- save_cache:
|
||||||
|
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
paths:
|
||||||
|
- ~/repo/packages/python-contract-wrappers/generated
|
||||||
build-website:
|
build-website:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
@@ -42,17 +51,7 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-multisig
|
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-utils
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-exchange-libs
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-erc20
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-erc721
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-erc1155
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-extensions
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-asset-proxy
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-exchange
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-exchange-forwarder
|
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-coordinator
|
|
||||||
test-contracts-geth:
|
test-contracts-geth:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:9-browsers
|
- image: circleci/node:9-browsers
|
||||||
@@ -64,17 +63,7 @@ jobs:
|
|||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
||||||
# initialized
|
# initialized
|
||||||
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test @0x/contracts-multisig
|
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-utils
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-exchange-libs
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-erc20
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-erc721
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-erc1155
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-extensions
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-asset-proxy
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-exchange
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-exchange-forwarder
|
|
||||||
- run: TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-coordinator
|
|
||||||
test-publish:
|
test-publish:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
@@ -95,20 +84,6 @@ jobs:
|
|||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn test:generate_docs:circleci
|
- run: yarn test:generate_docs:circleci
|
||||||
test-pipeline:
|
|
||||||
docker:
|
|
||||||
- image: circleci/node:9
|
|
||||||
- image: postgres:11-alpine
|
|
||||||
working_directory: ~/repo
|
|
||||||
steps:
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
|
||||||
- run: ZEROEX_DATA_PIPELINE_TEST_DB_URL='postgresql://postgres@localhost/postgres' yarn wsrun test:circleci @0x/pipeline
|
|
||||||
- save_cache:
|
|
||||||
key: coverage-pipeline-{{ .Environment.CIRCLE_SHA1 }}
|
|
||||||
paths:
|
|
||||||
- ~/repo/packages/pipeline/coverage/lcov.info
|
|
||||||
test-rest:
|
test-rest:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:9-browsers
|
- image: circleci/node:9-browsers
|
||||||
@@ -119,6 +94,8 @@ jobs:
|
|||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
||||||
- run: yarn wsrun test:circleci @0x/abi-gen
|
- run: yarn wsrun test:circleci @0x/abi-gen
|
||||||
|
- run: yarn wsrun test:circleci @0x/asset-buyer
|
||||||
|
- run: yarn wsrun test:circleci @0x/contract-artifacts
|
||||||
- run: yarn wsrun test:circleci @0x/assert
|
- run: yarn wsrun test:circleci @0x/assert
|
||||||
- run: yarn wsrun test:circleci @0x/base-contract
|
- run: yarn wsrun test:circleci @0x/base-contract
|
||||||
- run: yarn wsrun test:circleci @0x/connect
|
- run: yarn wsrun test:circleci @0x/connect
|
||||||
@@ -143,6 +120,10 @@ jobs:
|
|||||||
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- ~/repo/packages/assert/coverage/lcov.info
|
- ~/repo/packages/assert/coverage/lcov.info
|
||||||
|
- save_cache:
|
||||||
|
key: coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
paths:
|
||||||
|
- ~/repo/packages/asset-buyer/coverage/lcov.info
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
|
key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
@@ -201,21 +182,27 @@ jobs:
|
|||||||
- image: circleci/python
|
- image: circleci/python
|
||||||
- image: 0xorg/ganache-cli:2.2.2
|
- image: 0xorg/ganache-cli:2.2.2
|
||||||
- image: 0xorg/launch-kit-ci
|
- image: 0xorg/launch-kit-ci
|
||||||
command: |
|
environment:
|
||||||
yarn start:ts -p 3000:3000
|
RPC_URL: http://localhost:8545
|
||||||
|
NETWORK_ID: 50
|
||||||
|
WHITELIST_ALL_TOKENS: True
|
||||||
|
command: bash -c "until curl -sfd'{\"method\":\"net_listening\"}' http://localhost:8545 | grep true; do continue; done; forever ts/lib/index.js"
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: sudo chown -R circleci:circleci /usr/local/bin
|
- run: sudo chown -R circleci:circleci /usr/local/bin
|
||||||
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
|
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- restore_cache:
|
||||||
|
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run:
|
- run:
|
||||||
command: |
|
command: |
|
||||||
cd python-packages
|
cd python-packages
|
||||||
python -m ensurepip
|
python -m ensurepip
|
||||||
|
./pre_install
|
||||||
./install
|
./install
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- '/usr/local/bin'
|
- '/usr/local/bin'
|
||||||
- '/usr/local/lib/python3.7/site-packages'
|
- '/usr/local/lib/python3.7/site-packages'
|
||||||
@@ -256,14 +243,14 @@ jobs:
|
|||||||
- run: sudo chown -R circleci:circleci /usr/local/bin
|
- run: sudo chown -R circleci:circleci /usr/local/bin
|
||||||
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
|
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run:
|
- run:
|
||||||
command: |
|
command: |
|
||||||
cd python-packages/order_utils
|
cd python-packages/order_utils
|
||||||
python -m ensurepip
|
python -m ensurepip
|
||||||
python -m pip install .
|
python -m pip install .
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- '/usr/local/bin'
|
- '/usr/local/bin'
|
||||||
- '/usr/local/lib/python3.7/site-packages'
|
- '/usr/local/lib/python3.7/site-packages'
|
||||||
@@ -284,11 +271,14 @@ jobs:
|
|||||||
- run: sudo chown -R circleci:circleci /usr/local/bin
|
- run: sudo chown -R circleci:circleci /usr/local/bin
|
||||||
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
|
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- restore_cache:
|
||||||
|
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run:
|
- run:
|
||||||
command: |
|
command: |
|
||||||
python -m ensurepip
|
python -m ensurepip
|
||||||
cd python-packages
|
cd python-packages
|
||||||
|
./pre_install
|
||||||
./install
|
./install
|
||||||
./lint
|
./lint
|
||||||
static-tests:
|
static-tests:
|
||||||
@@ -318,6 +308,9 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
|
- coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
@@ -390,12 +383,11 @@ workflows:
|
|||||||
- test-contracts-ganache:
|
- test-contracts-ganache:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
- test-contracts-geth:
|
# TODO(albrow): Tests always fail on Geth right now because our fork
|
||||||
requires:
|
# is outdated. Uncomment once we have updated our Geth fork.
|
||||||
- build
|
# - test-contracts-geth:
|
||||||
- test-pipeline:
|
# requires:
|
||||||
requires:
|
# - build
|
||||||
- build
|
|
||||||
- test-rest:
|
- test-rest:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
@@ -415,6 +407,8 @@ workflows:
|
|||||||
- static-tests-python:
|
- static-tests-python:
|
||||||
requires:
|
requires:
|
||||||
- test-python
|
- test-python
|
||||||
- test-python
|
- test-python:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
# skip python tox run for now, as we don't yet have multiple test environments to support.
|
# skip python tox run for now, as we don't yet have multiple test environments to support.
|
||||||
#- test-rest-python
|
#- test-rest-python
|
||||||
|
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -1,7 +1,7 @@
|
|||||||
*.sol linguist-language=Solidity
|
*.sol linguist-language=Solidity
|
||||||
|
|
||||||
# Automatically collapse generated files in GitHub.
|
# Automatically collapse generated files in GitHub.
|
||||||
*.svg linguist-generated
|
*.svg linguist-generated=true
|
||||||
packages/contract-artifacts/artifacts/*json linguist-generated
|
packages/contract-artifacts/artifacts/*json linguist-generated=true
|
||||||
packages/abi-gen-wrappers/wrappers/*.ts liguist-generated
|
packages/abi-gen-wrappers/src/generated-wrappers/*.ts liguist-generated=true
|
||||||
|
|
||||||
|
80
.github/autolabeler.yml
vendored
80
.github/autolabeler.yml
vendored
@@ -1,43 +1,43 @@
|
|||||||
python: ['python-packages']
|
python: ['python-packages']
|
||||||
contracts: ['contracts']
|
contracts: ['contracts']
|
||||||
sol-doc: ['packages/sol-doc']
|
@0x/sol-doc: ['packages/sol-doc']
|
||||||
sol-resolver: ['packages/sol-resolver']
|
@0x/sol-resolver: ['packages/sol-resolver']
|
||||||
contracts-gen: ['packages/contracts-gen']
|
@0x/contracts-gen: ['packages/contracts-gen']
|
||||||
sra-spec: ['packages/sra-spec']
|
@0x/sra-spec: ['packages/sra-spec']
|
||||||
subproviders: ['packages/subproviders']
|
@0x/subproviders: ['packages/subproviders']
|
||||||
contract-addresses: ['packages/contract-addresses']
|
@0x/contract-addresses: ['packages/contract-addresses']
|
||||||
migrations: ['packages/migrations']
|
@0x/migrations: ['packages/migrations']
|
||||||
web3-wrapper: ['packages/web3-wrapper']
|
@0x/web3-wrapper: ['packages/web3-wrapper']
|
||||||
sol-compiler: ['packages/sol-compiler']
|
@0x/sol-compiler: ['packages/sol-compiler']
|
||||||
types: ['packages/types']
|
@0x/types: ['packages/types']
|
||||||
instant: ['packages/instant']
|
@0x/instant: ['packages/instant']
|
||||||
abi-gen-templates: ['packages/abi-gen-templates']
|
@0x/abi-gen-templates: ['packages/abi-gen-templates']
|
||||||
abi-gen: ['packages/abi-gen']
|
@0x/abi-gen: ['packages/abi-gen']
|
||||||
website: ['packages/website']
|
@0x/website: ['packages/website']
|
||||||
sol-coverage: ['packages/sol-coverage']
|
@0x/sol-coverage: ['packages/sol-coverage']
|
||||||
sol-profiler: ['packages/sol-profiler']
|
@0x/sol-profiler: ['packages/sol-profiler']
|
||||||
sol-trace: ['packages/sol-trace']
|
@0x/sol-trace: ['packages/sol-trace']
|
||||||
sol-tracing-utils: ['packages/sol-tracing-utils']
|
@0x/sol-tracing-utils: ['packages/sol-tracing-utils']
|
||||||
utils: ['packages/utils']
|
@0x/utils: ['packages/utils']
|
||||||
tslint-config: ['packages/tslint-config']
|
@0x/tslint-config: ['packages/tslint-config']
|
||||||
asset-buyer: ['packages/asset-buyer']
|
@0x/asset-buyer: ['packages/asset-buyer']
|
||||||
order-watcher: ['packages/order-watcher']
|
@0x/order-watcher: ['packages/order-watcher']
|
||||||
react-docs: ['packages/react-docs']
|
@0x/react-docs: ['packages/react-docs']
|
||||||
order-utils: ['packages/order-utils']
|
@0x/order-utils: ['packages/order-utils']
|
||||||
react-shared: ['packages/react-shared']
|
@0x/react-shared: ['packages/react-shared']
|
||||||
assert: ['packages/assert']
|
@0x/assert: ['packages/assert']
|
||||||
base-contract: ['packages/base-contract']
|
@0x/base-contract: ['packages/base-contract']
|
||||||
typescript-typings: ['packages/typescript-typings']
|
@0x/typescript-typings: ['packages/typescript-typings']
|
||||||
0x.js: ['packages/0x.js']
|
0x.js: ['packages/0x.js']
|
||||||
abi-gen-wrappers: ['packages/abi-gen-wrappers']
|
@0x/abi-gen-wrappers: ['packages/abi-gen-wrappers']
|
||||||
metacoin: ['packages/metacoin']
|
@0x/metacoin: ['packages/metacoin']
|
||||||
contract-artifacts: ['packages/contract-artifacts']
|
@0x/contract-artifacts: ['packages/contract-artifacts']
|
||||||
dev-utils: ['packages/dev-utils']
|
@0x/dev-utils: ['packages/dev-utils']
|
||||||
contract-wrappers: ['packages/contract-wrappers']
|
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||||
json-schemas: ['packages/json-schemas']
|
@0x/json-schemas: ['packages/json-schemas']
|
||||||
ethereum-types: ['ethereum-types']
|
@0x/ethereum-types: ['ethereum-types']
|
||||||
connect: ['packages/connect']
|
@0x/connect: ['packages/connect']
|
||||||
fill-scenarios: ['packages/fill-scenarios']
|
@0x/fill-scenarios: ['packages/fill-scenarios']
|
||||||
dev-tools-pages: ['packages/dev-tools-pages']
|
@0x/dev-tools-pages: ['packages/dev-tools-pages']
|
||||||
testnet-faucets: ['packages/testnet-faucets']
|
@0x/testnet-faucets: ['packages/testnet-faucets']
|
||||||
monorepo-scripts: ['packages/monorepo-scripts']
|
@0x/monorepo-scripts: ['packages/monorepo-scripts']
|
||||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@@ -94,11 +94,14 @@ contracts/erc721/generated-artifacts/
|
|||||||
contracts/erc1155/generated-artifacts/
|
contracts/erc1155/generated-artifacts/
|
||||||
contracts/extensions/generated-artifacts/
|
contracts/extensions/generated-artifacts/
|
||||||
contracts/exchange-forwarder/generated-artifacts/
|
contracts/exchange-forwarder/generated-artifacts/
|
||||||
|
contracts/dev-utils/generated-artifacts/
|
||||||
packages/sol-tracing-utils/test/fixtures/artifacts/
|
packages/sol-tracing-utils/test/fixtures/artifacts/
|
||||||
packages/metacoin/artifacts/
|
packages/metacoin/artifacts/
|
||||||
|
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||||
|
|
||||||
# generated contract wrappers
|
# generated contract wrappers
|
||||||
packages/abi-gen-wrappers/wrappers
|
packages/abi-gen-wrappers/src/generated-wrappers/
|
||||||
|
packages/python-contract-wrappers/generated/
|
||||||
contracts/coordinator/generated-wrappers/
|
contracts/coordinator/generated-wrappers/
|
||||||
contracts/exchange/generated-wrappers/
|
contracts/exchange/generated-wrappers/
|
||||||
contracts/asset-proxy/generated-wrappers/
|
contracts/asset-proxy/generated-wrappers/
|
||||||
@@ -110,8 +113,12 @@ contracts/erc721/generated-wrappers/
|
|||||||
contracts/erc1155/generated-wrappers/
|
contracts/erc1155/generated-wrappers/
|
||||||
contracts/extensions/generated-wrappers/
|
contracts/extensions/generated-wrappers/
|
||||||
contracts/exchange-forwarder/generated-wrappers/
|
contracts/exchange-forwarder/generated-wrappers/
|
||||||
|
contracts/dev-utils/generated-wrappers/
|
||||||
packages/metacoin/src/contract_wrappers
|
packages/metacoin/src/contract_wrappers
|
||||||
|
|
||||||
|
# cli test output
|
||||||
|
packages/abi-gen/test-cli/output
|
||||||
|
|
||||||
# solc-bin in sol-compiler
|
# solc-bin in sol-compiler
|
||||||
packages/sol-compiler/solc_bin/
|
packages/sol-compiler/solc_bin/
|
||||||
|
|
||||||
|
@@ -22,9 +22,9 @@ lib
|
|||||||
/contracts/extensions/generated-artifacts
|
/contracts/extensions/generated-artifacts
|
||||||
/contracts/exchange-forwarder/generated-wrappers
|
/contracts/exchange-forwarder/generated-wrappers
|
||||||
/contracts/exchange-forwarder/generated-artifacts
|
/contracts/exchange-forwarder/generated-artifacts
|
||||||
/packages/abi-gen-wrappers/src/generated-wrappers
|
/contracts/dev-utils/generated-wrappers
|
||||||
/packages/contract-artifacts/artifacts
|
/contracts/dev-utils/generated-artifacts
|
||||||
/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts
|
/packages/abi-gen/test-cli/output
|
||||||
/packages/json-schemas/schemas
|
/packages/json-schemas/schemas
|
||||||
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||||
/packages/metacoin/src/contract_wrappers
|
/packages/metacoin/src/contract_wrappers
|
||||||
|
@@ -11,10 +11,10 @@ packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff
|
|||||||
|
|
||||||
# Dev tools & setup
|
# Dev tools & setup
|
||||||
.circleci/ @LogvinovLeon
|
.circleci/ @LogvinovLeon
|
||||||
packages/abi-gen/ @LogvinovLeon
|
packages/abi-gen/ @feuGeneA
|
||||||
packages/base-contract/ @LogvinovLeon
|
packages/base-contract/ @xianny
|
||||||
packages/connect/ @fragosti
|
packages/connect/ @fragosti
|
||||||
packages/abi-gen-templates/ @LogvinovLeon
|
packages/abi-gen-templates/ @feuGeneA @xianny
|
||||||
packages/contract-addresses/ @albrow
|
packages/contract-addresses/ @albrow
|
||||||
packages/contract-artifacts/ @albrow
|
packages/contract-artifacts/ @albrow
|
||||||
packages/dev-utils/ @LogvinovLeon @fabioberger
|
packages/dev-utils/ @LogvinovLeon @fabioberger
|
||||||
@@ -23,6 +23,7 @@ packages/ethereum-types/ @LogvinovLeon
|
|||||||
packages/metacoin/ @LogvinovLeon
|
packages/metacoin/ @LogvinovLeon
|
||||||
packages/monorepo-scripts/ @fabioberger
|
packages/monorepo-scripts/ @fabioberger
|
||||||
packages/order-utils/ @fabioberger @LogvinovLeon
|
packages/order-utils/ @fabioberger @LogvinovLeon
|
||||||
|
packages/python-contract-wrappers/ @feuGeneA
|
||||||
packages/sol-compiler/ @LogvinovLeon
|
packages/sol-compiler/ @LogvinovLeon
|
||||||
packages/sol-coverage/ @LogvinovLeon
|
packages/sol-coverage/ @LogvinovLeon
|
||||||
packages/sol-profiler/ @LogvinovLeon
|
packages/sol-profiler/ @LogvinovLeon
|
||||||
@@ -36,5 +37,4 @@ python-packages/ @feuGeneA
|
|||||||
packages/utils/ @hysz
|
packages/utils/ @hysz
|
||||||
|
|
||||||
# Protocol/smart contracts
|
# Protocol/smart contracts
|
||||||
contracts/core/test/ @albrow
|
|
||||||
contracts/ @abandeali1 @hysz
|
contracts/ @abandeali1 @hysz
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<!--- Before submitting please check to see if this issue was already reported -->
|
<!--- Before submitting please check to see if this issue was already reported -->
|
||||||
|
|
||||||
<!--- Provide a general summary of the issue in the Title above -->
|
<!--- Prefix your issue title with the package name it relates to (e.g., `0x.js: ` or `general:`) -->
|
||||||
|
|
||||||
## Expected Behavior
|
## Expected Behavior
|
||||||
|
|
||||||
|
@@ -50,6 +50,7 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
|||||||
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [](https://www.npmjs.com/package/@0x/contracts-test-utils) | Typescript/Javascript shared utilities used for testing contracts |
|
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [](https://www.npmjs.com/package/@0x/contracts-test-utils) | Typescript/Javascript shared utilities used for testing contracts |
|
||||||
| [`@0x/contracts-utils`](/contracts/utils) | [](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts |
|
| [`@0x/contracts-utils`](/contracts/utils) | [](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts |
|
||||||
| [`@0x/contracts-coordinator`](/contracts/coordinator) | [](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator |
|
| [`@0x/contracts-coordinator`](/contracts/coordinator) | [](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator |
|
||||||
|
| [`@0x/contracts-dev-utils`](/contracts/dev-utils) | [](https://www.npmjs.com/package/@0x/contracts-dev-utils) | A contract contains utility functions for developers (such as validating many orders using a single eth_call) |
|
||||||
|
|
||||||
### Typescript/Javascript Packages
|
### Typescript/Javascript Packages
|
||||||
|
|
||||||
|
@@ -10,3 +10,7 @@
|
|||||||
| Forwarder | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) |
|
| Forwarder | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) |
|
||||||
| MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) |
|
| MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) |
|
||||||
| ZRXToken | [`@0x/contracts-erc20`](/contracts/erc20) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1) | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1) |
|
| ZRXToken | [`@0x/contracts-erc20`](/contracts/erc20) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1) | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1) |
|
||||||
|
|
||||||
|
#### Development
|
||||||
|
|
||||||
|
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `abi-gen-wrappers` package, which are generated from the artifact JSON. To ensure consistency, clean and rebuild `abi-gen-wrappers` after any changes to the artifact JSON.
|
||||||
|
@@ -1,4 +1,77 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "2.2.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.2.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add `LibAssetProxyIds` contract",
|
||||||
|
"pr": 1835
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases.",
|
||||||
|
"pr": 1852
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Implement StaticCallProxy",
|
||||||
|
"pr": 1863
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1563006338
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1558712885,
|
||||||
|
"version": "2.1.5",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557961111,
|
||||||
|
"version": "2.1.4",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557799313,
|
||||||
|
"version": "2.1.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.1.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
|
||||||
|
"pr": 1797
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1557507213
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.1.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1554997931
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,36 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.2.1 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.0 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Add `LibAssetProxyIds` contract (#1835)
|
||||||
|
* Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases. (#1852)
|
||||||
|
* Implement StaticCallProxy (#1863)
|
||||||
|
|
||||||
|
## v2.1.5 - _May 24, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.4 - _May 15, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.3 - _May 14, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.2 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
|
||||||
|
|
||||||
|
## v2.1.1 - _April 11, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v2.1.0 - _March 21, 2019_
|
## v2.1.0 - _March 21, 2019_
|
||||||
|
|
||||||
* Run Web3ProviderEngine without excess block polling (#1695)
|
* Run Web3ProviderEngine without excess block polling (#1695)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "./generated-artifacts",
|
"artifactsDir": "./generated-artifacts",
|
||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": true,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "constantinople",
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
"abi",
|
"abi",
|
||||||
|
"devdoc",
|
||||||
"evm.bytecode.object",
|
"evm.bytecode.object",
|
||||||
"evm.bytecode.sourceMap",
|
"evm.bytecode.sourceMap",
|
||||||
"evm.deployedBytecode.object",
|
"evm.deployedBytecode.object",
|
||||||
@@ -28,8 +29,10 @@
|
|||||||
"src/ERC721Proxy.sol",
|
"src/ERC721Proxy.sol",
|
||||||
"src/MixinAuthorizable.sol",
|
"src/MixinAuthorizable.sol",
|
||||||
"src/MultiAssetProxy.sol",
|
"src/MultiAssetProxy.sol",
|
||||||
|
"src/StaticCallProxy.sol",
|
||||||
"src/interfaces/IAssetData.sol",
|
"src/interfaces/IAssetData.sol",
|
||||||
"src/interfaces/IAssetProxy.sol",
|
"src/interfaces/IAssetProxy.sol",
|
||||||
"src/interfaces/IAuthorizable.sol"
|
"src/interfaces/IAuthorizable.sol",
|
||||||
|
"test/TestStaticCallTarget.sol"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.5;
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
import "./MixinAuthorizable.sol";
|
import "./MixinAuthorizable.sol";
|
||||||
|
|
||||||
@@ -28,6 +28,7 @@ contract ERC1155Proxy is
|
|||||||
// Id of this proxy.
|
// Id of this proxy.
|
||||||
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
|
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
|
||||||
|
|
||||||
|
// solhint-disable-next-line payable-fallback
|
||||||
function ()
|
function ()
|
||||||
external
|
external
|
||||||
{
|
{
|
||||||
@@ -58,11 +59,11 @@ contract ERC1155Proxy is
|
|||||||
// | | 100 | | 4. offset to data (*) |
|
// | | 100 | | 4. offset to data (*) |
|
||||||
// | Data | | | ids: |
|
// | Data | | | ids: |
|
||||||
// | | 132 | 32 | 1. ids Length |
|
// | | 132 | 32 | 1. ids Length |
|
||||||
// | | 164 | a | 2. ids Contents |
|
// | | 164 | a | 2. ids Contents |
|
||||||
// | | | | values: |
|
// | | | | values: |
|
||||||
// | | 164 + a | 32 | 1. values Length |
|
// | | 164 + a | 32 | 1. values Length |
|
||||||
// | | 196 + a | b | 2. values Contents |
|
// | | 196 + a | b | 2. values Contents |
|
||||||
// | | | | data |
|
// | | | | data: |
|
||||||
// | | 196 + a + b | 32 | 1. data Length |
|
// | | 196 + a + b | 32 | 1. data Length |
|
||||||
// | | 228 + a + b | c | 2. data Contents |
|
// | | 228 + a + b | c | 2. data Contents |
|
||||||
//
|
//
|
||||||
@@ -80,18 +81,18 @@ contract ERC1155Proxy is
|
|||||||
// | | 132 | | 5. offset to data (*) |
|
// | | 132 | | 5. offset to data (*) |
|
||||||
// | Data | | | ids: |
|
// | Data | | | ids: |
|
||||||
// | | 164 | 32 | 1. ids Length |
|
// | | 164 | 32 | 1. ids Length |
|
||||||
// | | 196 | a | 2. ids Contents |
|
// | | 196 | a | 2. ids Contents |
|
||||||
// | | | | values: |
|
// | | | | values: |
|
||||||
// | | 196 + a | 32 | 1. values Length |
|
// | | 196 + a | 32 | 1. values Length |
|
||||||
// | | 228 + a | b | 2. values Contents |
|
// | | 228 + a | b | 2. values Contents |
|
||||||
// | | | | data |
|
// | | | | data: |
|
||||||
// | | 228 + a + b | 32 | 1. data Length |
|
// | | 228 + a + b | 32 | 1. data Length |
|
||||||
// | | 260 + a + b | c | 2. data Contents |
|
// | | 260 + a + b | c | 2. data Contents |
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// (*): offset is computed from start of function parameters, so offset
|
// (*): offset is computed from start of function parameters, so offset
|
||||||
// by an additional 4 bytes in the calldata.
|
// by an additional 4 bytes in the calldata.
|
||||||
//
|
//
|
||||||
// (**): the `Offset` column is computed assuming no calldata compression;
|
// (**): the `Offset` column is computed assuming no calldata compression;
|
||||||
// offsets in the Data Area are dynamic and should be evaluated in
|
// offsets in the Data Area are dynamic and should be evaluated in
|
||||||
// real-time.
|
// real-time.
|
||||||
@@ -100,7 +101,7 @@ contract ERC1155Proxy is
|
|||||||
// the Params and Data section. This will result in a larger
|
// the Params and Data section. This will result in a larger
|
||||||
// offset to assetData.
|
// offset to assetData.
|
||||||
//
|
//
|
||||||
// Note: Table #1 and Table #2 exists in Calldata. We construct Table #3 in memory.
|
// Note: Table #1 and Table #2 exist in Calldata. We construct Table #3 in memory.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
assembly {
|
assembly {
|
||||||
@@ -114,7 +115,7 @@ contract ERC1155Proxy is
|
|||||||
// amount Amount of asset to transfer.
|
// amount Amount of asset to transfer.
|
||||||
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
|
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
|
||||||
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
|
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
|
||||||
|
|
||||||
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
|
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
|
||||||
// where k is the key left padded to 32 bytes and p is the storage slot
|
// where k is the key left padded to 32 bytes and p is the storage slot
|
||||||
mstore(0, caller)
|
mstore(0, caller)
|
||||||
@@ -131,71 +132,154 @@ contract ERC1155Proxy is
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct Table #3 in memory, starting at memory offset 0.
|
// Construct Table #3 in memory, starting at memory offset 0.
|
||||||
// The algorithm below maps asset data from Table #1 and Table #2 to Table #3, while
|
// The algorithm below maps calldata (Table #1) and assetData (Table #2) to memory (Table #3).
|
||||||
// scaling the `values` (Table #2) by `amount` (Table #1). Once Table #3 has
|
// Once Table #3 ha been constructed in memory, the destination erc1155 contract is called using this
|
||||||
// been constructed in memory, the destination erc1155 contract is called using this
|
// as its calldata. This process is divided into three steps, below.
|
||||||
// as its calldata. This process is divided into four steps, below.
|
|
||||||
|
////////// STEP 1/3 - Map calldata to memory (Table #1 -> Table #3) //////////
|
||||||
|
|
||||||
|
// Store the safeBatchTransferFrom function selector, which is computed using:
|
||||||
|
// bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"))
|
||||||
|
mstore(0, 0x2eb2c2d600000000000000000000000000000000000000000000000000000000)
|
||||||
|
|
||||||
|
// Copy `from` and `to` fields from calldata (Table #1) into memory (Table #3)
|
||||||
|
calldatacopy(
|
||||||
|
4, // aligned such that `from` and `to` are at the correct location for Table #3
|
||||||
|
36, // beginning of `from` field from Table #1
|
||||||
|
64 // 32 bytes for `from` + 32 bytes for `to` field
|
||||||
|
)
|
||||||
|
|
||||||
|
////////// STEP 2/3 - Map assetData to memory (Table #2 -> Table #3) //////////
|
||||||
|
|
||||||
////////// STEP 1/4 //////////
|
|
||||||
// Map relevant fields from assetData (Table #2) into memory (Table #3)
|
// Map relevant fields from assetData (Table #2) into memory (Table #3)
|
||||||
// The Contents column of Table #2 is the same as Table #3,
|
// The Contents column of Table #2 is the same as Table #3,
|
||||||
// beginning from parameter 3 - `offset to ids (*)`
|
// beginning from parameter 3 - `offset to ids (*)`
|
||||||
// The offsets in these rows are offset by 32 bytes in Table #3.
|
// The `values` from assetData (Table #2) are multiplied by `amount` (Table #1)
|
||||||
// Strategy:
|
// when they are copied into memory.
|
||||||
// 1. Copy the assetData into memory at offset 32
|
|
||||||
// 2. Increment by 32 the offsets to `ids`, `values`, and `data`
|
|
||||||
|
|
||||||
// Load offset to `assetData`
|
// Load offset to `assetData`
|
||||||
let assetDataOffset := calldataload(4)
|
let assetDataOffset := add(calldataload(4), 4)
|
||||||
|
|
||||||
// Load length in bytes of `assetData`, computed by:
|
// Load length in bytes of `assetData`
|
||||||
// 4 (function selector)
|
let assetDataLength := calldataload(assetDataOffset)
|
||||||
// + assetDataOffset
|
|
||||||
let assetDataLength := calldataload(add(4, assetDataOffset))
|
|
||||||
|
|
||||||
// This corresponds to the beginning of the Data Area for Table #3.
|
// Assert that the length of asset data:
|
||||||
// Computed by:
|
// 1. Must be at least 132 bytes (Table #2)
|
||||||
// 4 (function selector)
|
// 2. Must be a multiple of 32 (excluding the 4-byte selector)
|
||||||
// + assetDataOffset
|
if or(lt(assetDataLength, 132), mod(sub(assetDataLength, 4), 32)) {
|
||||||
// + 32 (length of assetData)
|
// Revert with `Error("INVALID_ASSET_DATA_LENGTH")`
|
||||||
calldatacopy(
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
32, // aligned such that "offset to ids" is at the correct location for Table #3
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
add(36, assetDataOffset), // beginning of asset data contents
|
mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000)
|
||||||
assetDataLength // length of asset data
|
mstore(96, 0)
|
||||||
)
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
// Increment by 32 the offsets to `ids`, `values`, and `data`
|
// End of asset data in calldata
|
||||||
mstore(68, add(mload(68), 32))
|
// +32 for length field
|
||||||
mstore(100, add(mload(100), 32))
|
let assetDataEnd := add(assetDataOffset, add(assetDataLength, 32))
|
||||||
mstore(132, add(mload(132), 32))
|
if gt(assetDataEnd, calldatasize()) {
|
||||||
|
// Revert with `Error("INVALID_ASSET_DATA_END")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
// Record the address of the destination erc1155 asset for later.
|
// Load offset to parameters section in asset data
|
||||||
let assetAddress := and(
|
let paramsInAssetDataOffset := add(assetDataOffset, 36)
|
||||||
mload(36),
|
|
||||||
0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
|
|
||||||
)
|
|
||||||
|
|
||||||
////////// STEP 2/4 //////////
|
// Offset of end of Data Area in memory.
|
||||||
|
// This value will grow as we construct Table #3.
|
||||||
|
let dataAreaEndOffset := 164
|
||||||
|
|
||||||
|
// Load amount by which to scale values
|
||||||
let amount := calldataload(100)
|
let amount := calldataload(100)
|
||||||
let valuesOffset := add(mload(100), 4) // add 4 for calldata offset
|
|
||||||
let valuesLengthInBytes := mul(
|
// Store pointer to `ids` (Table #3)
|
||||||
mload(valuesOffset),
|
// Subtract 4 for `safeBatchTransferFrom` selector
|
||||||
32
|
mstore(68, sub(dataAreaEndOffset, 4))
|
||||||
|
|
||||||
|
// Ensure length of `ids` does not overflow
|
||||||
|
let idsOffset := add(paramsInAssetDataOffset, calldataload(add(assetDataOffset, 68)))
|
||||||
|
let idsLength := calldataload(idsOffset)
|
||||||
|
let idsLengthInBytes := mul(idsLength, 32)
|
||||||
|
if sub(div(idsLengthInBytes, 32), idsLength) {
|
||||||
|
// Revert with `Error("UINT256_OVERFLOW")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure `ids` does not resolve to outside of `assetData`
|
||||||
|
let idsBegin := add(idsOffset, 32)
|
||||||
|
let idsEnd := add(idsBegin, idsLengthInBytes)
|
||||||
|
if gt(idsEnd, assetDataEnd) {
|
||||||
|
// Revert with `Error("INVALID_IDS_OFFSET")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x00000012494e56414c49445f4944535f4f464653455400000000000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy `ids` from `assetData` (Table #2) to memory (Table #3)
|
||||||
|
calldatacopy(
|
||||||
|
dataAreaEndOffset,
|
||||||
|
idsOffset,
|
||||||
|
add(idsLengthInBytes, 32)
|
||||||
)
|
)
|
||||||
|
dataAreaEndOffset := add(dataAreaEndOffset, add(idsLengthInBytes, 32))
|
||||||
|
|
||||||
|
// Store pointer to `values` (Table #3)
|
||||||
|
// Subtract 4 for `safeBatchTrasferFrom` selector
|
||||||
|
mstore(100, sub(dataAreaEndOffset, 4))
|
||||||
|
|
||||||
|
// Ensure length of `values` does not overflow
|
||||||
|
let valuesOffset := add(paramsInAssetDataOffset, calldataload(add(assetDataOffset, 100)))
|
||||||
|
let valuesLength := calldataload(valuesOffset)
|
||||||
|
let valuesLengthInBytes := mul(valuesLength, 32)
|
||||||
|
if sub(div(valuesLengthInBytes, 32), valuesLength) {
|
||||||
|
// Revert with `Error("UINT256_OVERFLOW")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure `values` does not resolve to outside of `assetData`
|
||||||
let valuesBegin := add(valuesOffset, 32)
|
let valuesBegin := add(valuesOffset, 32)
|
||||||
let valuesEnd := add(valuesBegin, valuesLengthInBytes)
|
let valuesEnd := add(valuesBegin, valuesLengthInBytes)
|
||||||
for { let tokenValueOffset := valuesBegin }
|
if gt(valuesEnd, assetDataEnd) {
|
||||||
lt(tokenValueOffset, valuesEnd)
|
// Revert with `Error("INVALID_VALUES_OFFSET")`
|
||||||
{ tokenValueOffset := add(tokenValueOffset, 32) }
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x00000015494e56414c49445f56414c5545535f4f464653455400000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store length of `values`
|
||||||
|
mstore(dataAreaEndOffset, valuesLength)
|
||||||
|
dataAreaEndOffset := add(dataAreaEndOffset, 32)
|
||||||
|
|
||||||
|
// Scale and store elements of `values`
|
||||||
|
for { let currentValueOffset := valuesBegin }
|
||||||
|
lt(currentValueOffset, valuesEnd)
|
||||||
|
{ currentValueOffset := add(currentValueOffset, 32) }
|
||||||
{
|
{
|
||||||
// Load token value and generate scaled value
|
// Load value and generate scaled value
|
||||||
let tokenValue := mload(tokenValueOffset)
|
let currentValue := calldataload(currentValueOffset)
|
||||||
let scaledTokenValue := mul(tokenValue, amount)
|
let currentValueScaled := mul(currentValue, amount)
|
||||||
|
|
||||||
// Revert if `amount` != 0 and multiplication resulted in an overflow
|
// Revert if `amount` != 0 and multiplication resulted in an overflow
|
||||||
if iszero(or(
|
if iszero(or(
|
||||||
iszero(amount),
|
iszero(amount),
|
||||||
eq(div(scaledTokenValue, amount), tokenValue)
|
eq(div(currentValueScaled, amount), currentValue)
|
||||||
)) {
|
)) {
|
||||||
// Revert with `Error("UINT256_OVERFLOW")`
|
// Revert with `Error("UINT256_OVERFLOW")`
|
||||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
@@ -205,33 +289,57 @@ contract ERC1155Proxy is
|
|||||||
revert(0, 100)
|
revert(0, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// There was no overflow, update `tokenValue` with its scaled counterpart
|
// There was no overflow, store the scaled token value
|
||||||
mstore(tokenValueOffset, scaledTokenValue)
|
mstore(dataAreaEndOffset, currentValueScaled)
|
||||||
|
dataAreaEndOffset := add(dataAreaEndOffset, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////// STEP 3/4 //////////
|
// Store pointer to `data` (Table #3)
|
||||||
// Store the safeBatchTransferFrom function selector,
|
// Subtract 4 for `safeBatchTrasferFrom` selector
|
||||||
// and copy `from`/`to` fields from Table #1 to Table #3.
|
mstore(132, sub(dataAreaEndOffset, 4))
|
||||||
|
|
||||||
// The function selector is computed using:
|
// Ensure `data` does not resolve to outside of `assetData`
|
||||||
// bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"))
|
let dataOffset := add(paramsInAssetDataOffset, calldataload(add(assetDataOffset, 132)))
|
||||||
mstore(0, 0x2eb2c2d600000000000000000000000000000000000000000000000000000000)
|
let dataLengthInBytes := calldataload(dataOffset)
|
||||||
|
let dataBegin := add(dataOffset, 32)
|
||||||
|
let dataEnd := add(dataBegin, dataLengthInBytes)
|
||||||
|
if gt(dataEnd, assetDataEnd) {
|
||||||
|
// Revert with `Error("INVALID_DATA_OFFSET")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x00000013494e56414c49445f444154415f4f4646534554000000000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
// Copy `from` and `to` fields from Table #1 to Table #3
|
// Copy `data` from `assetData` (Table #2) to memory (Table #3)
|
||||||
calldatacopy(
|
calldatacopy(
|
||||||
4, // aligned such that `from` and `to` are at the correct location for Table #3
|
dataAreaEndOffset,
|
||||||
36, // beginning of `from` field from Table #1
|
dataOffset,
|
||||||
64 // 32 bytes for `from` + 32 bytes for `to` field
|
add(dataLengthInBytes, 32)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update the end of data offset to be word-aligned
|
||||||
|
let dataLengthInWords := div(add(dataLengthInBytes, 31), 32)
|
||||||
|
let dataLengthInBytesWordAligned := mul(dataLengthInWords, 32)
|
||||||
|
dataAreaEndOffset := add(dataAreaEndOffset, add(dataLengthInBytesWordAligned, 32))
|
||||||
|
|
||||||
|
////////// STEP 3/3 - Execute Transfer //////////
|
||||||
|
// Load the address of the destination erc1155 contract from asset data (Table #2)
|
||||||
|
// +32 bytes for assetData Length
|
||||||
|
// +4 bytes for assetProxyId
|
||||||
|
let assetAddress := and(
|
||||||
|
calldataload(add(assetDataOffset, 36)),
|
||||||
|
0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
|
||||||
)
|
)
|
||||||
|
|
||||||
////////// STEP 4/4 //////////
|
|
||||||
// Call into the destination erc1155 contract using as calldata Table #3 (constructed in-memory above)
|
// Call into the destination erc1155 contract using as calldata Table #3 (constructed in-memory above)
|
||||||
let success := call(
|
let success := call(
|
||||||
gas, // forward all gas
|
gas, // forward all gas
|
||||||
assetAddress, // call address of erc1155 asset
|
assetAddress, // call address of erc1155 asset
|
||||||
0, // don't send any ETH
|
0, // don't send any ETH
|
||||||
0, // pointer to start of input
|
0, // pointer to start of input
|
||||||
add(assetDataLength, 32), // length of input (Table #3) is 32 bytes longer than `assetData` (Table #2)
|
dataAreaEndOffset, // length of input is the end of the Data Area (Table #3)
|
||||||
0, // write output over memory that won't be reused
|
0, // write output over memory that won't be reused
|
||||||
0 // don't copy output to memory
|
0 // don't copy output to memory
|
||||||
)
|
)
|
||||||
@@ -245,7 +353,7 @@ contract ERC1155Proxy is
|
|||||||
)
|
)
|
||||||
revert(0, returndatasize())
|
revert(0, returndatasize())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if call was successful
|
// Return if call was successful
|
||||||
return(0, 0)
|
return(0, 0)
|
||||||
}
|
}
|
||||||
|
207
contracts/asset-proxy/contracts/src/StaticCallProxy.sol
Normal file
207
contracts/asset-proxy/contracts/src/StaticCallProxy.sol
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
|
|
||||||
|
contract StaticCallProxy {
|
||||||
|
|
||||||
|
// Id of this proxy.
|
||||||
|
bytes4 constant internal PROXY_ID = bytes4(keccak256("StaticCall(address,bytes,bytes32)"));
|
||||||
|
|
||||||
|
// solhint-disable-next-line payable-fallback
|
||||||
|
function ()
|
||||||
|
external
|
||||||
|
{
|
||||||
|
assembly {
|
||||||
|
// The first 4 bytes of calldata holds the function selector
|
||||||
|
let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
|
||||||
|
|
||||||
|
// `transferFrom` will be called with the following parameters:
|
||||||
|
// assetData Encoded byte array.
|
||||||
|
// from Address to transfer asset from.
|
||||||
|
// to Address to transfer asset to.
|
||||||
|
// amount Amount of asset to transfer.
|
||||||
|
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
|
||||||
|
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
|
||||||
|
|
||||||
|
// `transferFrom`.
|
||||||
|
// The function is marked `external`, so no abi decoding is done for
|
||||||
|
// us. Instead, we expect the `calldata` memory to contain the
|
||||||
|
// following:
|
||||||
|
//
|
||||||
|
// | Area | Offset | Length | Contents |
|
||||||
|
// |----------|--------|---------|-------------------------------------|
|
||||||
|
// | Header | 0 | 4 | function selector |
|
||||||
|
// | Params | | 4 * 32 | function parameters: |
|
||||||
|
// | | 4 | | 1. offset to assetData (*) |
|
||||||
|
// | | 36 | | 2. from |
|
||||||
|
// | | 68 | | 3. to |
|
||||||
|
// | | 100 | | 4. amount |
|
||||||
|
// | Data | | | assetData: |
|
||||||
|
// | | 132 | 32 | assetData Length |
|
||||||
|
// | | 164 | ** | assetData Contents |
|
||||||
|
//
|
||||||
|
// (*): offset is computed from start of function parameters, so offset
|
||||||
|
// by an additional 4 bytes in the calldata.
|
||||||
|
//
|
||||||
|
// (**): see table below to compute length of assetData Contents
|
||||||
|
// (***): Note that the `from`, `to`, and `amount` params in calldata are ignored in this function.
|
||||||
|
//
|
||||||
|
// WARNING: The ABIv2 specification allows additional padding between
|
||||||
|
// the Params and Data section. This will result in a larger
|
||||||
|
// offset to assetData.
|
||||||
|
|
||||||
|
// Load offset to `assetData`
|
||||||
|
let assetDataOffset := add(calldataload(4), 4)
|
||||||
|
|
||||||
|
// Validate length of `assetData`
|
||||||
|
let assetDataLen := calldataload(assetDataOffset)
|
||||||
|
if or(lt(assetDataLen, 100), mod(sub(assetDataLen, 4), 32)) {
|
||||||
|
// Revert with `Error("INVALID_ASSET_DATA_LENGTH")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that `assetData` ends inside of calldata
|
||||||
|
let assetDataEnd := add(assetDataOffset, add(assetDataLen, 32))
|
||||||
|
if gt(assetDataEnd, calldatasize()) {
|
||||||
|
// Revert with `Error("INVALID_ASSET_DATA_END")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000)
|
||||||
|
mstore(96, 0)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asset data is encoded as follows:
|
||||||
|
// | Area | Offset | Length | Contents |
|
||||||
|
// |----------|-------------|---------|--------------------------------------|
|
||||||
|
// | Header | 0 | 4 | assetProxyId |
|
||||||
|
// | Params | | 4 * 32 | function parameters: |
|
||||||
|
// | | 4 | | 1. address of callTarget |
|
||||||
|
// | | 36 | | 2. offset to staticCallData (*) |
|
||||||
|
// | | 68 | | 3. expected 32 byte hash of output |
|
||||||
|
// | Data | | | staticCallData: |
|
||||||
|
// | | 100 | 32 | 1. staticCallData Length |
|
||||||
|
// | | 132 | a | 2. staticCallData Contents |
|
||||||
|
|
||||||
|
// In order to find the offset to `staticCallData`, we must add:
|
||||||
|
// assetDataOffset
|
||||||
|
// + 32 (assetData len)
|
||||||
|
// + 4 (proxyId)
|
||||||
|
// + 32 (callTarget)
|
||||||
|
let paramsInAssetDataOffset := add(assetDataOffset, 36)
|
||||||
|
let staticCallDataOffset := add(paramsInAssetDataOffset, calldataload(add(assetDataOffset, 68)))
|
||||||
|
|
||||||
|
// Load length of `staticCallData`
|
||||||
|
let staticCallDataLen := calldataload(staticCallDataOffset)
|
||||||
|
|
||||||
|
// Ensure `staticCallData` does not begin to outside of `assetData`
|
||||||
|
let staticCallDataBegin := add(staticCallDataOffset, 32)
|
||||||
|
let staticCallDataEnd := add(staticCallDataBegin, staticCallDataLen)
|
||||||
|
if gt(staticCallDataEnd, assetDataEnd) {
|
||||||
|
// Revert with `Error("INVALID_STATIC_CALL_DATA_OFFSET")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x0000001f494e56414c49445f5354415449435f43414c4c5f444154415f4f4646)
|
||||||
|
mstore(96, 0x5345540000000000000000000000000000000000000000000000000000000000)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy `staticCallData` into memory
|
||||||
|
calldatacopy(
|
||||||
|
0, // memory can be safely overwritten from beginning
|
||||||
|
staticCallDataBegin, // start of `staticCallData`
|
||||||
|
staticCallDataLen // copy the entire `staticCallData`
|
||||||
|
)
|
||||||
|
|
||||||
|
// In order to find the offset to `callTarget`, we must add:
|
||||||
|
// assetDataOffset
|
||||||
|
// + 32 (assetData len)
|
||||||
|
// + 4 (proxyId)
|
||||||
|
let callTarget := and(
|
||||||
|
calldataload(add(assetDataOffset, 36)),
|
||||||
|
0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perform `callTarget.staticcall(staticCallData)`
|
||||||
|
let success := staticcall(
|
||||||
|
gas, // forward all gas
|
||||||
|
callTarget, // call address `callTarget`
|
||||||
|
0, // pointer to start of input
|
||||||
|
staticCallDataLen, // length of input
|
||||||
|
0, // start of memory can be safely overwritten
|
||||||
|
0 // don't copy output to memory
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copy entire output to start of memory
|
||||||
|
let outputLen := returndatasize()
|
||||||
|
returndatacopy(
|
||||||
|
0, // copy to memory at 0
|
||||||
|
0, // copy from return data at 0
|
||||||
|
outputLen // copy all return data
|
||||||
|
)
|
||||||
|
|
||||||
|
// Revert with reason given by `callTarget` if staticcall is unsuccessful
|
||||||
|
if iszero(success) {
|
||||||
|
revert(0, outputLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate hash of output
|
||||||
|
let callResultHash := keccak256(0, outputLen)
|
||||||
|
|
||||||
|
// In order to find the offset to `expectedCallResultHash`, we must add:
|
||||||
|
// assetDataOffset
|
||||||
|
// + 32 (assetData len)
|
||||||
|
// + 4 (proxyId)
|
||||||
|
// + 32 (callTarget)
|
||||||
|
// + 32 (staticCallDataOffset)
|
||||||
|
let expectedResultHash := calldataload(add(assetDataOffset, 100))
|
||||||
|
|
||||||
|
if sub(callResultHash, expectedResultHash) {
|
||||||
|
// Revert with `Error("UNEXPECTED_STATIC_CALL_RESULT")`
|
||||||
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
mstore(64, 0x0000001d554e45585045435445445f5354415449435f43414c4c5f524553554c)
|
||||||
|
mstore(96, 0x5400000000000000000000000000000000000000000000000000000000000000)
|
||||||
|
revert(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if output matched expected output
|
||||||
|
return(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert if undefined function is called
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Gets the proxy id associated with the proxy address.
|
||||||
|
/// @return Proxy id.
|
||||||
|
function getProxyId()
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
returns (bytes4)
|
||||||
|
{
|
||||||
|
return PROXY_ID;
|
||||||
|
}
|
||||||
|
}
|
@@ -26,19 +26,33 @@ pragma experimental ABIEncoderV2;
|
|||||||
// This argument is ABI encoded as one of the methods of this interface.
|
// This argument is ABI encoded as one of the methods of this interface.
|
||||||
interface IAssetData {
|
interface IAssetData {
|
||||||
|
|
||||||
function ERC20Token(address tokenContract)
|
function ERC20Token(address tokenAddress)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
function ERC721Token(
|
function ERC721Token(
|
||||||
address tokenContract,
|
address tokenAddress,
|
||||||
uint256 tokenId
|
uint256 tokenId
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
|
function ERC1155Assets(
|
||||||
|
address tokenAddress,
|
||||||
|
uint256[] calldata tokenIds,
|
||||||
|
uint256[] calldata tokenValues,
|
||||||
|
bytes calldata callbackData
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
function MultiAsset(
|
function MultiAsset(
|
||||||
uint256[] calldata amounts,
|
uint256[] calldata amounts,
|
||||||
bytes[] calldata nestedAssetData
|
bytes[] calldata nestedAssetData
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
|
function StaticCall(
|
||||||
|
address callTarget,
|
||||||
|
bytes calldata staticCallData,
|
||||||
|
bytes32 callResultHash
|
||||||
|
)
|
||||||
|
external;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
|
||||||
|
contract LibAssetProxyIds {
|
||||||
|
|
||||||
|
// AssetProxy Ids are equiavalent the first 4 bytes of the keccak256 hash of the function signature assigned to each AssetProxy.
|
||||||
|
|
||||||
|
// ERC20Token(address)
|
||||||
|
bytes4 constant public ERC20_PROXY_ID = 0xf47261b0;
|
||||||
|
|
||||||
|
// ERC721Token(address,uint256)
|
||||||
|
bytes4 constant public ERC721_PROXY_ID = 0x02571792;
|
||||||
|
|
||||||
|
// ERC1155Assets(address,uint256[],uint256[],bytes)
|
||||||
|
bytes4 constant public ERC1155_PROXY_ID = 0xa7cb5fb7;
|
||||||
|
|
||||||
|
// MultiAsset(uint256[],bytes[])
|
||||||
|
bytes4 constant public MULTI_ASSET_PROXY_ID = 0x94cfcdd7;
|
||||||
|
|
||||||
|
// StaticCall(address,bytes,bytes32)
|
||||||
|
bytes4 constant public STATIC_CALL_PROXY_ID = 0xc339d10a;
|
||||||
|
}
|
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract TestStaticCallTarget {
|
||||||
|
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
uint256 internal _state;
|
||||||
|
|
||||||
|
function updateState()
|
||||||
|
external
|
||||||
|
{
|
||||||
|
_state++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertEvenNumber(uint256 target)
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
{
|
||||||
|
require(
|
||||||
|
target % 2 == 0,
|
||||||
|
"TARGET_NOT_EVEN"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOddNumber(uint256 target)
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
returns (bool isOdd)
|
||||||
|
{
|
||||||
|
isOdd = target % 2 == 1;
|
||||||
|
return isOdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
function noInputFunction()
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
{
|
||||||
|
assert(msg.data.length == 4 && msg.data.readBytes4(0) == bytes4(keccak256("noInputFunction()")));
|
||||||
|
}
|
||||||
|
|
||||||
|
function dynamicInputFunction(bytes calldata a)
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
{
|
||||||
|
bytes memory abiEncodedData = abi.encodeWithSignature("dynamicInputFunction(bytes)", a);
|
||||||
|
assert(msg.data.equals(abiEncodedData));
|
||||||
|
}
|
||||||
|
|
||||||
|
function returnComplexType(uint256 a, uint256 b)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes memory result)
|
||||||
|
{
|
||||||
|
result = abi.encodePacked(
|
||||||
|
address(this),
|
||||||
|
a,
|
||||||
|
b
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-asset-proxy",
|
"name": "@0x/contracts-asset-proxy",
|
||||||
"version": "2.1.0",
|
"version": "2.2.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
"coverage:report:text": "istanbul report text",
|
"coverage:report:text": "istanbul report text",
|
||||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy).json",
|
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy|StaticCallProxy|TestStaticCallTarget).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -46,12 +47,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^2.0.8",
|
"@0x/abi-gen": "^2.1.1",
|
||||||
"@0x/contracts-gen": "^1.0.7",
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
"@0x/contracts-test-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
"@0x/dev-utils": "^2.2.0",
|
"@0x/dev-utils": "^2.2.4",
|
||||||
"@0x/sol-compiler": "^3.1.5",
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
"@0x/tslint-config": "^3.0.0",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@@ -67,17 +68,18 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.4",
|
"@0x/base-contract": "^5.1.1",
|
||||||
"@0x/contracts-erc1155": "^1.1.0",
|
"@0x/contracts-erc1155": "^1.1.8",
|
||||||
"@0x/contracts-erc20": "^2.1.0",
|
"@0x/contracts-erc20": "^2.2.7",
|
||||||
"@0x/contracts-erc721": "^2.1.0",
|
"@0x/contracts-erc721": "^2.1.8",
|
||||||
"@0x/contracts-utils": "^3.1.0",
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
"@0x/order-utils": "^7.1.1",
|
"@0x/order-utils": "^8.2.1",
|
||||||
"@0x/types": "^2.2.1",
|
"@0x/types": "^2.4.0",
|
||||||
"@0x/typescript-typings": "^4.2.1",
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
"@0x/utils": "^4.3.0",
|
"@0x/utils": "^4.4.0",
|
||||||
"@0x/web3-wrapper": "^6.0.4",
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
"ethereum-types": "^2.1.1",
|
"ethereum-types": "^2.1.3",
|
||||||
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@@ -13,13 +13,17 @@ import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
|||||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||||
|
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||||
|
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
|
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
|
||||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||||
|
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||||
IAssetData: IAssetData as ContractArtifact,
|
IAssetData: IAssetData as ContractArtifact,
|
||||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||||
|
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@@ -11,3 +11,5 @@ export * from '../generated-wrappers/i_asset_proxy';
|
|||||||
export * from '../generated-wrappers/i_authorizable';
|
export * from '../generated-wrappers/i_authorizable';
|
||||||
export * from '../generated-wrappers/mixin_authorizable';
|
export * from '../generated-wrappers/mixin_authorizable';
|
||||||
export * from '../generated-wrappers/multi_asset_proxy';
|
export * from '../generated-wrappers/multi_asset_proxy';
|
||||||
|
export * from '../generated-wrappers/static_call_proxy';
|
||||||
|
export * from '../generated-wrappers/test_static_call_target';
|
||||||
|
@@ -53,16 +53,18 @@ describe('Authorizable', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should allow owner to add an authorized address', async () => {
|
it('should allow owner to add an authorized address', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||||
expect(isAuthorized).to.be.true();
|
expect(isAuthorized).to.be.true();
|
||||||
});
|
});
|
||||||
it('should throw if owner attempts to authorize a duplicate address', async () => {
|
it('should throw if owner attempts to authorize a duplicate address', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
return expectTransactionFailedAsync(
|
return expectTransactionFailedAsync(
|
||||||
@@ -74,8 +76,9 @@ describe('Authorizable', () => {
|
|||||||
|
|
||||||
describe('removeAuthorizedAddress', () => {
|
describe('removeAuthorizedAddress', () => {
|
||||||
it('should throw if not called by owner', async () => {
|
it('should throw if not called by owner', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
return expectTransactionFailedAsync(
|
return expectTransactionFailedAsync(
|
||||||
@@ -87,14 +90,14 @@ describe('Authorizable', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should allow owner to remove an authorized address', async () => {
|
it('should allow owner to remove an authorized address', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||||
@@ -113,8 +116,9 @@ describe('Authorizable', () => {
|
|||||||
|
|
||||||
describe('removeAuthorizedAddressAtIndex', () => {
|
describe('removeAuthorizedAddressAtIndex', () => {
|
||||||
it('should throw if not called by owner', async () => {
|
it('should throw if not called by owner', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const index = new BigNumber(0);
|
const index = new BigNumber(0);
|
||||||
@@ -126,8 +130,9 @@ describe('Authorizable', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw if index is >= authorities.length', async () => {
|
it('should throw if index is >= authorities.length', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const index = new BigNumber(1);
|
const index = new BigNumber(1);
|
||||||
@@ -150,12 +155,14 @@ describe('Authorizable', () => {
|
|||||||
it('should throw if address at index does not match target', async () => {
|
it('should throw if address at index does not match target', async () => {
|
||||||
const address1 = address;
|
const address1 = address;
|
||||||
const address2 = notOwner;
|
const address2 = notOwner;
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address1, { from: owner }),
|
address1,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address2, { from: owner }),
|
address2,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const address1Index = new BigNumber(0);
|
const address1Index = new BigNumber(0);
|
||||||
@@ -167,15 +174,16 @@ describe('Authorizable', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should allow owner to remove an authorized address', async () => {
|
it('should allow owner to remove an authorized address', async () => {
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
address,
|
||||||
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const index = new BigNumber(0);
|
const index = new BigNumber(0);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync(
|
||||||
await authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
address,
|
||||||
from: owner,
|
index,
|
||||||
}),
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||||
@@ -187,20 +195,17 @@ describe('Authorizable', () => {
|
|||||||
it('should return all authorized addresses', async () => {
|
it('should return all authorized addresses', async () => {
|
||||||
const initial = await authorizable.getAuthorizedAddresses.callAsync();
|
const initial = await authorizable.getAuthorizedAddresses.callAsync();
|
||||||
expect(initial).to.have.length(0);
|
expect(initial).to.have.length(0);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, {
|
address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
|
const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
|
||||||
expect(afterAdd).to.have.length(1);
|
expect(afterAdd).to.have.length(1);
|
||||||
expect(afterAdd).to.include(address);
|
expect(afterAdd).to.include(address);
|
||||||
|
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
address,
|
||||||
await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
{ from: owner },
|
||||||
from: owner,
|
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
|
const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -44,16 +44,8 @@ import {
|
|||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
const assetProxyInterface = new IAssetProxyContract(
|
const assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
|
||||||
artifacts.IAssetProxy.compilerOutput.abi,
|
const assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
|
||||||
constants.NULL_ADDRESS,
|
|
||||||
provider,
|
|
||||||
);
|
|
||||||
const assetDataInterface = new IAssetDataContract(
|
|
||||||
artifacts.IAssetData.compilerOutput.abi,
|
|
||||||
constants.NULL_ADDRESS,
|
|
||||||
provider,
|
|
||||||
);
|
|
||||||
|
|
||||||
// tslint:disable:no-unnecessary-type-assertion
|
// tslint:disable:no-unnecessary-type-assertion
|
||||||
describe('Asset Transfer Proxies', () => {
|
describe('Asset Transfer Proxies', () => {
|
||||||
@@ -111,72 +103,62 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Configure ERC20Proxy
|
// Configure ERC20Proxy
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
|
authorized,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
|
multiAssetProxy.address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Configure ERC721Proxy
|
// Configure ERC721Proxy
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc721Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
|
authorized,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc721Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
|
multiAssetProxy.address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Configure ERC115Proxy
|
// Configure ERC115Proxy
|
||||||
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
|
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
|
||||||
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
|
authorized,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
|
multiAssetProxy.address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Configure MultiAssetProxy
|
// Configure MultiAssetProxy
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await multiAssetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
|
authorized,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await multiAssetProxy.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
|
erc20Proxy.address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await multiAssetProxy.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
|
erc721Proxy.address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await multiAssetProxy.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc1155Proxy.address, {
|
erc1155Proxy.address,
|
||||||
from: owner,
|
{ from: owner },
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -206,31 +188,32 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await noReturnErc20Token.setBalance.awaitTransactionSuccessAsync(
|
||||||
await noReturnErc20Token.setBalance.sendTransactionAsync(fromAddress, constants.INITIAL_ERC20_BALANCE),
|
fromAddress,
|
||||||
|
constants.INITIAL_ERC20_BALANCE,
|
||||||
|
{
|
||||||
|
from: owner,
|
||||||
|
},
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await noReturnErc20Token.approve.awaitTransactionSuccessAsync(
|
||||||
await noReturnErc20Token.approve.sendTransactionAsync(
|
erc20Proxy.address,
|
||||||
erc20Proxy.address,
|
constants.INITIAL_ERC20_ALLOWANCE,
|
||||||
constants.INITIAL_ERC20_ALLOWANCE,
|
{ from: fromAddress },
|
||||||
{ from: fromAddress },
|
|
||||||
),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await multipleReturnErc20Token.setBalance.awaitTransactionSuccessAsync(
|
||||||
await multipleReturnErc20Token.setBalance.sendTransactionAsync(
|
fromAddress,
|
||||||
fromAddress,
|
constants.INITIAL_ERC20_BALANCE,
|
||||||
constants.INITIAL_ERC20_BALANCE,
|
{
|
||||||
),
|
from: owner,
|
||||||
|
},
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await multipleReturnErc20Token.approve.awaitTransactionSuccessAsync(
|
||||||
await multipleReturnErc20Token.approve.sendTransactionAsync(
|
erc20Proxy.address,
|
||||||
erc20Proxy.address,
|
constants.INITIAL_ERC20_ALLOWANCE,
|
||||||
constants.INITIAL_ERC20_ALLOWANCE,
|
{ from: fromAddress },
|
||||||
{ from: fromAddress },
|
|
||||||
),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -419,10 +402,10 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
toAddress,
|
toAddress,
|
||||||
amount,
|
amount,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc20TokenA.approve.awaitTransactionSuccessAsync(
|
||||||
await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
|
erc20Proxy.address,
|
||||||
from: fromAddress,
|
allowance,
|
||||||
}),
|
{ from: fromAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
@@ -451,10 +434,10 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
toAddress,
|
toAddress,
|
||||||
amount,
|
amount,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await noReturnErc20Token.approve.awaitTransactionSuccessAsync(
|
||||||
await noReturnErc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
|
erc20Proxy.address,
|
||||||
from: fromAddress,
|
allowance,
|
||||||
}),
|
{ from: fromAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
|
const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
|
||||||
@@ -692,10 +675,10 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
|
const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
|
||||||
expect(ownerFromAsset).to.be.equal(fromAddress);
|
expect(ownerFromAsset).to.be.equal(fromAddress);
|
||||||
// Remove transfer approval for fromAddress.
|
// Remove transfer approval for fromAddress.
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await erc721TokenA.approve.awaitTransactionSuccessAsync(
|
||||||
await erc721TokenA.approve.sendTransactionAsync(constants.NULL_ADDRESS, erc721AFromTokenId, {
|
constants.NULL_ADDRESS,
|
||||||
from: fromAddress,
|
erc721AFromTokenId,
|
||||||
}),
|
{ from: fromAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
// Perform a transfer; expect this to fail.
|
// Perform a transfer; expect this to fail.
|
||||||
|
250
contracts/asset-proxy/test/static_call_proxy.ts
Normal file
250
contracts/asset-proxy/test/static_call_proxy.ts
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
expectTransactionFailedAsync,
|
||||||
|
expectTransactionFailedWithoutReasonAsync,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||||
|
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
|
import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
|
||||||
|
describe('StaticCallProxy', () => {
|
||||||
|
const amount = constants.ZERO_AMOUNT;
|
||||||
|
let fromAddress: string;
|
||||||
|
let toAddress: string;
|
||||||
|
|
||||||
|
let staticCallProxy: IAssetProxyContract;
|
||||||
|
let staticCallTarget: TestStaticCallTargetContract;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
before(async () => {
|
||||||
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
[fromAddress, toAddress] = accounts.slice(0, 2);
|
||||||
|
const staticCallProxyWithoutTransferFrom = await StaticCallProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.StaticCallProxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults);
|
||||||
|
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestStaticCallTarget,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('general', () => {
|
||||||
|
it('should revert if undefined function is called', async () => {
|
||||||
|
const undefinedSelector = '0x01020304';
|
||||||
|
await expectTransactionFailedWithoutReasonAsync(
|
||||||
|
web3Wrapper.sendTransactionAsync({
|
||||||
|
from: fromAddress,
|
||||||
|
to: staticCallProxy.address,
|
||||||
|
value: constants.ZERO_AMOUNT,
|
||||||
|
data: undefinedSelector,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should have an id of 0xc339d10a', async () => {
|
||||||
|
const proxyId = await staticCallProxy.getProxyId.callAsync();
|
||||||
|
const expectedProxyId = AssetProxyId.StaticCall;
|
||||||
|
expect(proxyId).to.equal(expectedProxyId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('transferFrom', () => {
|
||||||
|
it('should revert if assetData lies outside the bounds of calldata', async () => {
|
||||||
|
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData(
|
||||||
|
assetData,
|
||||||
|
fromAddress,
|
||||||
|
toAddress,
|
||||||
|
amount,
|
||||||
|
);
|
||||||
|
const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
|
||||||
|
const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
|
||||||
|
const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
|
||||||
|
const invalidOffsetToAssetData = ethUtil.bufferToHex(paddedTxDataEndBuffer).slice(2);
|
||||||
|
const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304';
|
||||||
|
const badTxData = `${txData.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`;
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
web3Wrapper.sendTransactionAsync({
|
||||||
|
to: staticCallProxy.address,
|
||||||
|
from: fromAddress,
|
||||||
|
data: badTxData,
|
||||||
|
}),
|
||||||
|
RevertReason.InvalidAssetDataEnd,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert if the length of assetData, excluding the proxyId, is not a multiple of 32', async () => {
|
||||||
|
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = `${assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
)}01`;
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.InvalidAssetDataLength,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert if the length of assetData is less than 100 bytes', async () => {
|
||||||
|
const staticCallData = constants.NULL_BYTES;
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils
|
||||||
|
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||||
|
.slice(0, -128);
|
||||||
|
const assetDataByteLen = (assetData.length - 2) / 2;
|
||||||
|
expect((assetDataByteLen - 4) % 32).to.equal(0);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.InvalidAssetDataLength,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert if the offset to `staticCallData` points to outside of assetData', async () => {
|
||||||
|
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
|
||||||
|
const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
|
||||||
|
const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
|
||||||
|
const invalidOffsetToStaticCallData = ethUtil.bufferToHex(paddedAssetDataEndBuffer).slice(2);
|
||||||
|
const newStaticCallData = '0000000000000000000000000000000000000000000000000000000000000304';
|
||||||
|
const badAssetData = `${assetData.replace(
|
||||||
|
offsetToStaticCallData,
|
||||||
|
invalidOffsetToStaticCallData,
|
||||||
|
)}${newStaticCallData}`;
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.InvalidStaticCallDataOffset,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert if the callTarget attempts to write to state', async () => {
|
||||||
|
const staticCallData = staticCallTarget.updateState.getABIEncodedTransactionData();
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await expectTransactionFailedWithoutReasonAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
|
||||||
|
const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.TargetNotEven,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert if the hash of the output is different than expected expected', async () => {
|
||||||
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
|
||||||
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.UnexpectedStaticCallResult,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should be successful if a function call with no inputs is successful', async () => {
|
||||||
|
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
|
});
|
||||||
|
it('should be successful if a function call with one static input returns the correct value', async () => {
|
||||||
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||||
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
|
});
|
||||||
|
it('should be successful if a function with one dynamic input is successful', async () => {
|
||||||
|
const dynamicInput = '0x0102030405060708';
|
||||||
|
const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput);
|
||||||
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
|
});
|
||||||
|
it('should be successful if a function call returns a complex type', async () => {
|
||||||
|
const a = new BigNumber(1);
|
||||||
|
const b = new BigNumber(2);
|
||||||
|
const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b);
|
||||||
|
const abiEncoder = new AbiEncoder.DynamicBytes({
|
||||||
|
name: '',
|
||||||
|
type: 'bytes',
|
||||||
|
});
|
||||||
|
const aHex = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||||
|
const bHex = '0000000000000000000000000000000000000000000000000000000000000002';
|
||||||
|
const expectedResults = `${staticCallTarget.address}${aHex}${bHex}`;
|
||||||
|
const offset = '0000000000000000000000000000000000000000000000000000000000000020';
|
||||||
|
const encodedExpectedResultWithOffset = `0x${offset}${abiEncoder.encode(expectedResults).slice(2)}`;
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(
|
||||||
|
ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
|
||||||
|
);
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -36,11 +36,7 @@ export class ERC1155ProxyWrapper {
|
|||||||
const allArtifacts = _.merge(artifacts, erc1155Artifacts);
|
const allArtifacts = _.merge(artifacts, erc1155Artifacts);
|
||||||
this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
|
this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
|
||||||
this._dummyTokenWrappers = [];
|
this._dummyTokenWrappers = [];
|
||||||
this._assetProxyInterface = new IAssetProxyContract(
|
this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
|
||||||
artifacts.IAssetProxy.compilerOutput.abi,
|
|
||||||
constants.NULL_ADDRESS,
|
|
||||||
provider,
|
|
||||||
);
|
|
||||||
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
||||||
this._contractOwnerAddress = contractOwnerAddress;
|
this._contractOwnerAddress = contractOwnerAddress;
|
||||||
this._fungibleTokenIds = [];
|
this._fungibleTokenIds = [];
|
||||||
@@ -84,6 +80,66 @@ export class ERC1155ProxyWrapper {
|
|||||||
this._validateProxyContractExistsOrThrow();
|
this._validateProxyContractExistsOrThrow();
|
||||||
return this._proxyIdIfExists as string;
|
return this._proxyIdIfExists as string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @dev generates abi-encoded tx data for transferring erc1155 fungible/non-fungible tokens.
|
||||||
|
* @param from source address
|
||||||
|
* @param to destination address
|
||||||
|
* @param contractAddress address of erc155 contract
|
||||||
|
* @param tokensToTransfer array of erc1155 tokens to transfer
|
||||||
|
* @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
|
||||||
|
* @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
|
||||||
|
* @param receiverCallbackData callback data if `to` is a contract
|
||||||
|
* @param authorizedSender sender of `transferFrom` transaction
|
||||||
|
* @param extraData extra data to append to `transferFrom` transaction. Optional.
|
||||||
|
* @return abi encoded tx data.
|
||||||
|
*/
|
||||||
|
public getTransferFromAbiEncodedTxData(
|
||||||
|
from: string,
|
||||||
|
to: string,
|
||||||
|
contractAddress: string,
|
||||||
|
tokensToTransfer: BigNumber[],
|
||||||
|
valuesToTransfer: BigNumber[],
|
||||||
|
valueMultiplier: BigNumber,
|
||||||
|
receiverCallbackData: string,
|
||||||
|
authorizedSender: string,
|
||||||
|
assetData_?: string,
|
||||||
|
): string {
|
||||||
|
this._validateProxyContractExistsOrThrow();
|
||||||
|
const assetData =
|
||||||
|
assetData_ === undefined
|
||||||
|
? assetDataUtils.encodeERC1155AssetData(
|
||||||
|
contractAddress,
|
||||||
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
)
|
||||||
|
: assetData_;
|
||||||
|
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
|
assetData,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
valueMultiplier,
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dev transfers erc1155 fungible/non-fungible tokens.
|
||||||
|
* @param txData: abi-encoded tx data
|
||||||
|
* @param authorizedSender sender of `transferFrom` transaction
|
||||||
|
*/
|
||||||
|
public async transferFromRawAsync(
|
||||||
|
txData: string,
|
||||||
|
authorizedSender: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const txHash = await this._web3Wrapper.sendTransactionAsync({
|
||||||
|
to: (this._proxyContract as ERC1155ProxyContract).address,
|
||||||
|
data: txData,
|
||||||
|
from: authorizedSender,
|
||||||
|
gas: 300000,
|
||||||
|
});
|
||||||
|
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @dev transfers erc1155 fungible/non-fungible tokens.
|
* @dev transfers erc1155 fungible/non-fungible tokens.
|
||||||
* @param from source address
|
* @param from source address
|
||||||
@@ -106,20 +162,20 @@ export class ERC1155ProxyWrapper {
|
|||||||
valueMultiplier: BigNumber,
|
valueMultiplier: BigNumber,
|
||||||
receiverCallbackData: string,
|
receiverCallbackData: string,
|
||||||
authorizedSender: string,
|
authorizedSender: string,
|
||||||
extraData?: string,
|
assetData_?: string,
|
||||||
): Promise<string> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
this._validateProxyContractExistsOrThrow();
|
this._validateProxyContractExistsOrThrow();
|
||||||
let encodedAssetData = assetDataUtils.encodeERC1155AssetData(
|
const assetData =
|
||||||
contractAddress,
|
assetData_ === undefined
|
||||||
tokensToTransfer,
|
? assetDataUtils.encodeERC1155AssetData(
|
||||||
valuesToTransfer,
|
contractAddress,
|
||||||
receiverCallbackData,
|
tokensToTransfer,
|
||||||
);
|
valuesToTransfer,
|
||||||
if (!_.isUndefined(extraData)) {
|
receiverCallbackData,
|
||||||
encodedAssetData = `${encodedAssetData}${extraData}`;
|
)
|
||||||
}
|
: assetData_;
|
||||||
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
encodedAssetData,
|
assetData,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
valueMultiplier,
|
valueMultiplier,
|
||||||
@@ -128,46 +184,9 @@ export class ERC1155ProxyWrapper {
|
|||||||
to: (this._proxyContract as ERC1155ProxyContract).address,
|
to: (this._proxyContract as ERC1155ProxyContract).address,
|
||||||
data,
|
data,
|
||||||
from: authorizedSender,
|
from: authorizedSender,
|
||||||
|
gas: 300000,
|
||||||
});
|
});
|
||||||
return txHash;
|
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @dev transfers erc1155 fungible/non-fungible tokens.
|
|
||||||
* @param from source address
|
|
||||||
* @param to destination address
|
|
||||||
* @param contractAddress address of erc155 contract
|
|
||||||
* @param tokensToTransfer array of erc1155 tokens to transfer
|
|
||||||
* @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
|
|
||||||
* @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
|
|
||||||
* @param receiverCallbackData callback data if `to` is a contract
|
|
||||||
* @param authorizedSender sender of `transferFrom` transaction
|
|
||||||
* @param extraData extra data to append to `transferFrom` transaction. Optional.
|
|
||||||
* @return tranasction receipt with decoded logs.
|
|
||||||
*/
|
|
||||||
public async transferFromWithLogsAsync(
|
|
||||||
from: string,
|
|
||||||
to: string,
|
|
||||||
contractAddress: string,
|
|
||||||
tokensToTransfer: BigNumber[],
|
|
||||||
valuesToTransfer: BigNumber[],
|
|
||||||
valueMultiplier: BigNumber,
|
|
||||||
receiverCallbackData: string,
|
|
||||||
authorizedSender: string,
|
|
||||||
extraData?: string,
|
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
|
||||||
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(
|
|
||||||
await this.transferFromAsync(
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
contractAddress,
|
|
||||||
tokensToTransfer,
|
|
||||||
valuesToTransfer,
|
|
||||||
valueMultiplier,
|
|
||||||
receiverCallbackData,
|
|
||||||
authorizedSender,
|
|
||||||
extraData,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return txReceipt;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -199,10 +218,10 @@ export class ERC1155ProxyWrapper {
|
|||||||
// Mint tokens for each owner for this token
|
// Mint tokens for each owner for this token
|
||||||
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress])) {
|
if (fungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
|
||||||
fungibleHoldingsByOwner[tokenOwnerAddress] = {};
|
fungibleHoldingsByOwner[tokenOwnerAddress] = {};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) {
|
if (fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
|
||||||
fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
|
fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
|
||||||
}
|
}
|
||||||
fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] =
|
fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] =
|
||||||
@@ -221,13 +240,13 @@ export class ERC1155ProxyWrapper {
|
|||||||
const tokenIdAsString = tokenId.toString();
|
const tokenIdAsString = tokenId.toString();
|
||||||
this._nonFungibleTokenIds.push(tokenIdAsString);
|
this._nonFungibleTokenIds.push(tokenIdAsString);
|
||||||
_.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => {
|
_.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => {
|
||||||
if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) {
|
if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
|
nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) {
|
if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
|
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString])) {
|
if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] === undefined) {
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = [];
|
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = [];
|
||||||
}
|
}
|
||||||
this._nfts.push({ id: nftIds[i], tokenId });
|
this._nfts.push({ id: nftIds[i], tokenId });
|
||||||
@@ -278,26 +297,25 @@ export class ERC1155ProxyWrapper {
|
|||||||
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
||||||
// Fungible tokens
|
// Fungible tokens
|
||||||
for (const tokenId of this._fungibleTokenIds) {
|
for (const tokenId of this._fungibleTokenIds) {
|
||||||
if (_.isUndefined(tokenHoldingsByOwner[tokenOwnerAddress])) {
|
if (tokenHoldingsByOwner[tokenOwnerAddress] === undefined) {
|
||||||
tokenHoldingsByOwner[tokenOwnerAddress] = {};
|
tokenHoldingsByOwner[tokenOwnerAddress] = {};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress])) {
|
if (tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
|
||||||
tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
|
tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
|
||||||
}
|
}
|
||||||
tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++];
|
tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++];
|
||||||
}
|
}
|
||||||
// Non-fungible tokens
|
// Non-fungible tokens
|
||||||
for (const nft of this._nfts) {
|
for (const nft of this._nfts) {
|
||||||
if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) {
|
if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
|
nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress])) {
|
if (nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
|
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
_.isUndefined(
|
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] ===
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()],
|
undefined
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = [];
|
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = [];
|
||||||
}
|
}
|
||||||
@@ -348,25 +366,25 @@ export class ERC1155ProxyWrapper {
|
|||||||
const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {
|
const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {
|
||||||
return wrapper.getContract().address === contractAddress;
|
return wrapper.getContract().address === contractAddress;
|
||||||
});
|
});
|
||||||
if (_.isUndefined(tokenWrapper)) {
|
if (tokenWrapper === undefined) {
|
||||||
throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`);
|
throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`);
|
||||||
}
|
}
|
||||||
return tokenWrapper;
|
return tokenWrapper;
|
||||||
}
|
}
|
||||||
private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract {
|
private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract {
|
||||||
const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress);
|
const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress);
|
||||||
if (_.isUndefined(tokenContractIfExists)) {
|
if (tokenContractIfExists === undefined) {
|
||||||
throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`);
|
throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`);
|
||||||
}
|
}
|
||||||
return tokenContractIfExists.getContract();
|
return tokenContractIfExists.getContract();
|
||||||
}
|
}
|
||||||
private _validateDummyTokenContractsExistOrThrow(): void {
|
private _validateDummyTokenContractsExistOrThrow(): void {
|
||||||
if (_.isUndefined(this._dummyTokenWrappers)) {
|
if (this._dummyTokenWrappers === undefined) {
|
||||||
throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"');
|
throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _validateProxyContractExistsOrThrow(): void {
|
private _validateProxyContractExistsOrThrow(): void {
|
||||||
if (_.isUndefined(this._proxyContract)) {
|
if (this._proxyContract === undefined) {
|
||||||
throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"');
|
throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@ import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contra
|
|||||||
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
|
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
|
||||||
import { assetDataUtils } from '@0x/order-utils';
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
||||||
import { ZeroExProvider } from 'ethereum-types';
|
import { ZeroExProvider } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import { artifacts, ERC20ProxyContract } from '../../src';
|
|||||||
export class ERC20Wrapper {
|
export class ERC20Wrapper {
|
||||||
private readonly _tokenOwnerAddresses: string[];
|
private readonly _tokenOwnerAddresses: string[];
|
||||||
private readonly _contractOwnerAddress: string;
|
private readonly _contractOwnerAddress: string;
|
||||||
private readonly _web3Wrapper: Web3Wrapper;
|
|
||||||
private readonly _provider: ZeroExProvider;
|
private readonly _provider: ZeroExProvider;
|
||||||
private readonly _dummyTokenContracts: DummyERC20TokenContract[];
|
private readonly _dummyTokenContracts: DummyERC20TokenContract[];
|
||||||
private _proxyContract?: ERC20ProxyContract;
|
private _proxyContract?: ERC20ProxyContract;
|
||||||
@@ -25,7 +23,6 @@ export class ERC20Wrapper {
|
|||||||
*/
|
*/
|
||||||
constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
|
constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
|
||||||
this._dummyTokenContracts = [];
|
this._dummyTokenContracts = [];
|
||||||
this._web3Wrapper = new Web3Wrapper(provider);
|
|
||||||
this._provider = provider;
|
this._provider = provider;
|
||||||
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
||||||
this._contractOwnerAddress = contractOwnerAddress;
|
this._contractOwnerAddress = contractOwnerAddress;
|
||||||
@@ -67,20 +64,16 @@ export class ERC20Wrapper {
|
|||||||
this._validateProxyContractExistsOrThrow();
|
this._validateProxyContractExistsOrThrow();
|
||||||
for (const dummyTokenContract of this._dummyTokenContracts) {
|
for (const dummyTokenContract of this._dummyTokenContracts) {
|
||||||
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await dummyTokenContract.setBalance.awaitTransactionSuccessAsync(
|
||||||
await dummyTokenContract.setBalance.sendTransactionAsync(
|
tokenOwnerAddress,
|
||||||
tokenOwnerAddress,
|
constants.INITIAL_ERC20_BALANCE,
|
||||||
constants.INITIAL_ERC20_BALANCE,
|
{ from: this._contractOwnerAddress },
|
||||||
{ from: this._contractOwnerAddress },
|
|
||||||
),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await dummyTokenContract.approve.awaitTransactionSuccessAsync(
|
||||||
await dummyTokenContract.approve.sendTransactionAsync(
|
(this._proxyContract as ERC20ProxyContract).address,
|
||||||
(this._proxyContract as ERC20ProxyContract).address,
|
constants.INITIAL_ERC20_ALLOWANCE,
|
||||||
constants.INITIAL_ERC20_ALLOWANCE,
|
{ from: tokenOwnerAddress },
|
||||||
{ from: tokenOwnerAddress },
|
|
||||||
),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -93,10 +86,10 @@ export class ERC20Wrapper {
|
|||||||
}
|
}
|
||||||
public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
|
public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
|
||||||
const tokenContract = this._getTokenContractFromAssetData(assetData);
|
const tokenContract = this._getTokenContractFromAssetData(assetData);
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.setBalance.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, {
|
userAddress,
|
||||||
from: this._contractOwnerAddress,
|
amount,
|
||||||
}),
|
{ from: this._contractOwnerAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -109,10 +102,10 @@ export class ERC20Wrapper {
|
|||||||
public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
|
public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
|
||||||
const tokenContract = this._getTokenContractFromAssetData(assetData);
|
const tokenContract = this._getTokenContractFromAssetData(assetData);
|
||||||
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
|
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.approve.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, {
|
proxyAddress,
|
||||||
from: userAddress,
|
amount,
|
||||||
}),
|
{ from: userAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -133,7 +126,7 @@ export class ERC20Wrapper {
|
|||||||
_.forEach(balances, (balance, balanceIndex) => {
|
_.forEach(balances, (balance, balanceIndex) => {
|
||||||
const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
|
const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
|
||||||
const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
|
const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
|
||||||
if (_.isUndefined(balancesByOwner[tokenOwnerAddress])) {
|
if (balancesByOwner[tokenOwnerAddress] === undefined) {
|
||||||
balancesByOwner[tokenOwnerAddress] = {};
|
balancesByOwner[tokenOwnerAddress] = {};
|
||||||
}
|
}
|
||||||
const wrappedBalance = new BigNumber(balance);
|
const wrappedBalance = new BigNumber(balance);
|
||||||
@@ -142,7 +135,7 @@ export class ERC20Wrapper {
|
|||||||
return balancesByOwner;
|
return balancesByOwner;
|
||||||
}
|
}
|
||||||
public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
|
public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
|
||||||
if (!_.isUndefined(this._dummyTokenContracts)) {
|
if (this._dummyTokenContracts !== undefined) {
|
||||||
this._dummyTokenContracts.push(dummy);
|
this._dummyTokenContracts.push(dummy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,18 +153,18 @@ export class ERC20Wrapper {
|
|||||||
const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData);
|
const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData);
|
||||||
const tokenAddress = erc20ProxyData.tokenAddress;
|
const tokenAddress = erc20ProxyData.tokenAddress;
|
||||||
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
|
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
|
||||||
if (_.isUndefined(tokenContractIfExists)) {
|
if (tokenContractIfExists === undefined) {
|
||||||
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
|
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
|
||||||
}
|
}
|
||||||
return tokenContractIfExists;
|
return tokenContractIfExists;
|
||||||
}
|
}
|
||||||
private _validateDummyTokenContractsExistOrThrow(): void {
|
private _validateDummyTokenContractsExistOrThrow(): void {
|
||||||
if (_.isUndefined(this._dummyTokenContracts)) {
|
if (this._dummyTokenContracts === undefined) {
|
||||||
throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
|
throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _validateProxyContractExistsOrThrow(): void {
|
private _validateProxyContractExistsOrThrow(): void {
|
||||||
if (_.isUndefined(this._proxyContract)) {
|
if (this._proxyContract === undefined) {
|
||||||
throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
|
throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@ import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/cont
|
|||||||
import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils';
|
import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils';
|
||||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
||||||
import { ZeroExProvider } from 'ethereum-types';
|
import { ZeroExProvider } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
@@ -11,14 +10,12 @@ import { artifacts, ERC721ProxyContract } from '../../src';
|
|||||||
export class ERC721Wrapper {
|
export class ERC721Wrapper {
|
||||||
private readonly _tokenOwnerAddresses: string[];
|
private readonly _tokenOwnerAddresses: string[];
|
||||||
private readonly _contractOwnerAddress: string;
|
private readonly _contractOwnerAddress: string;
|
||||||
private readonly _web3Wrapper: Web3Wrapper;
|
|
||||||
private readonly _provider: ZeroExProvider;
|
private readonly _provider: ZeroExProvider;
|
||||||
private readonly _dummyTokenContracts: DummyERC721TokenContract[];
|
private readonly _dummyTokenContracts: DummyERC721TokenContract[];
|
||||||
private _proxyContract?: ERC721ProxyContract;
|
private _proxyContract?: ERC721ProxyContract;
|
||||||
private _proxyIdIfExists?: string;
|
private _proxyIdIfExists?: string;
|
||||||
private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
|
private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
|
||||||
constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
|
constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
|
||||||
this._web3Wrapper = new Web3Wrapper(provider);
|
|
||||||
this._provider = provider;
|
this._provider = provider;
|
||||||
this._dummyTokenContracts = [];
|
this._dummyTokenContracts = [];
|
||||||
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
||||||
@@ -62,12 +59,12 @@ export class ERC721Wrapper {
|
|||||||
for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
|
for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
|
||||||
const tokenId = generatePseudoRandomSalt();
|
const tokenId = generatePseudoRandomSalt();
|
||||||
await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
|
await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
|
||||||
if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) {
|
if (this._initialTokenIdsByOwner[tokenOwnerAddress] === undefined) {
|
||||||
this._initialTokenIdsByOwner[tokenOwnerAddress] = {
|
this._initialTokenIdsByOwner[tokenOwnerAddress] = {
|
||||||
[dummyTokenContract.address]: [],
|
[dummyTokenContract.address]: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address])) {
|
if (this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] === undefined) {
|
||||||
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
|
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
|
||||||
}
|
}
|
||||||
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
|
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
|
||||||
@@ -91,20 +88,20 @@ export class ERC721Wrapper {
|
|||||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||||
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
|
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
|
||||||
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
|
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.setApprovalForAll.sendTransactionAsync(proxyAddress, isApproved, {
|
proxyAddress,
|
||||||
from: tokenOwner,
|
isApproved,
|
||||||
}),
|
{ from: tokenOwner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
|
public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
|
||||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||||
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
|
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.approve.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.approve.sendTransactionAsync(to, tokenId, {
|
to,
|
||||||
from: tokenOwner,
|
tokenId,
|
||||||
}),
|
{ from: tokenOwner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -115,28 +112,29 @@ export class ERC721Wrapper {
|
|||||||
userAddress: string,
|
userAddress: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.transferFrom.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.transferFrom.sendTransactionAsync(currentOwner, userAddress, tokenId, {
|
currentOwner,
|
||||||
from: currentOwner,
|
userAddress,
|
||||||
}),
|
tokenId,
|
||||||
|
{ from: currentOwner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
|
public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
|
||||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.mint.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.mint.sendTransactionAsync(userAddress, tokenId, {
|
userAddress,
|
||||||
from: this._contractOwnerAddress,
|
tokenId,
|
||||||
}),
|
{ from: this._contractOwnerAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
|
public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
|
||||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
await tokenContract.burn.awaitTransactionSuccessAsync(
|
||||||
await tokenContract.burn.sendTransactionAsync(owner, tokenId, {
|
owner,
|
||||||
from: this._contractOwnerAddress,
|
tokenId,
|
||||||
}),
|
{ from: this._contractOwnerAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -189,12 +187,12 @@ export class ERC721Wrapper {
|
|||||||
_.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
|
_.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
|
||||||
const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
|
const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
|
||||||
const tokenId = tokenInfo[ownerIndex].tokenId;
|
const tokenId = tokenInfo[ownerIndex].tokenId;
|
||||||
if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress])) {
|
if (tokenIdsByOwner[tokenOwnerAddress] === undefined) {
|
||||||
tokenIdsByOwner[tokenOwnerAddress] = {
|
tokenIdsByOwner[tokenOwnerAddress] = {
|
||||||
[tokenAddress]: [],
|
[tokenAddress]: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress][tokenAddress])) {
|
if (tokenIdsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
|
||||||
tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
|
tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
|
||||||
}
|
}
|
||||||
tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
|
tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
|
||||||
@@ -210,18 +208,18 @@ export class ERC721Wrapper {
|
|||||||
}
|
}
|
||||||
private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
|
private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
|
||||||
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
|
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
|
||||||
if (_.isUndefined(tokenContractIfExists)) {
|
if (tokenContractIfExists === undefined) {
|
||||||
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
|
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
|
||||||
}
|
}
|
||||||
return tokenContractIfExists;
|
return tokenContractIfExists;
|
||||||
}
|
}
|
||||||
private _validateDummyTokenContractsExistOrThrow(): void {
|
private _validateDummyTokenContractsExistOrThrow(): void {
|
||||||
if (_.isUndefined(this._dummyTokenContracts)) {
|
if (this._dummyTokenContracts === undefined) {
|
||||||
throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
|
throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _validateProxyContractExistsOrThrow(): void {
|
private _validateProxyContractExistsOrThrow(): void {
|
||||||
if (_.isUndefined(this._proxyContract)) {
|
if (this._proxyContract === undefined) {
|
||||||
throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
|
throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
"generated-artifacts/IAssetProxy.json",
|
"generated-artifacts/IAssetProxy.json",
|
||||||
"generated-artifacts/IAuthorizable.json",
|
"generated-artifacts/IAuthorizable.json",
|
||||||
"generated-artifacts/MixinAuthorizable.json",
|
"generated-artifacts/MixinAuthorizable.json",
|
||||||
"generated-artifacts/MultiAssetProxy.json"
|
"generated-artifacts/MultiAssetProxy.json",
|
||||||
|
"generated-artifacts/StaticCallProxy.json",
|
||||||
|
"generated-artifacts/TestStaticCallTarget.json"
|
||||||
],
|
],
|
||||||
"exclude": ["./deploy/solc/solc_bin"]
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,72 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "2.0.6",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1563006338,
|
||||||
|
"version": "2.0.5",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1558712885,
|
||||||
|
"version": "2.0.4",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557961111,
|
||||||
|
"version": "2.0.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557799313,
|
||||||
|
"version": "2.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557507213,
|
||||||
|
"version": "2.0.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Make `decodeOrdersFromFillData`, `getCoordinatorApprovalHash`, and `getTransactionHash` public",
|
||||||
|
"pr": 1729
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Make `assertValidTransactionOrdersApproval` internal",
|
||||||
|
"pr": 1729
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1554997931
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,35 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.0.6 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.0.5 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.0.4 - _May 24, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.0.3 - _May 15, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.0.2 - _May 14, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.0.1 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.0.0 - _April 11, 2019_
|
||||||
|
|
||||||
|
* Make `decodeOrdersFromFillData`, `getCoordinatorApprovalHash`, and `getTransactionHash` public (#1729)
|
||||||
|
* Make `assertValidTransactionOrdersApproval` internal (#1729)
|
||||||
|
|
||||||
## v1.1.0 - _March 21, 2019_
|
## v1.1.0 - _March 21, 2019_
|
||||||
|
|
||||||
* Run Web3ProviderEngine without excess block polling (#1695)
|
* Run Web3ProviderEngine without excess block polling (#1695)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "./generated-artifacts",
|
"artifactsDir": "./generated-artifacts",
|
||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": true,
|
"useDockerisedSolc": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "constantinople",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
"abi",
|
"abi",
|
||||||
|
"devdoc",
|
||||||
"evm.bytecode.object",
|
"evm.bytecode.object",
|
||||||
"evm.bytecode.sourceMap",
|
"evm.bytecode.sourceMap",
|
||||||
"evm.deployedBytecode.object",
|
"evm.deployedBytecode.object",
|
||||||
@@ -21,10 +22,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"contracts": [
|
"contracts": ["src/Coordinator.sol", "src/registry/CoordinatorRegistry.sol"]
|
||||||
"src/Coordinator.sol",
|
|
||||||
"src/registry/CoordinatorRegistry.sol",
|
|
||||||
"test/TestLibs.sol",
|
|
||||||
"test/TestMixins.sol"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@@ -58,7 +58,7 @@ contract MixinCoordinatorApprovalVerifier is
|
|||||||
view
|
view
|
||||||
{
|
{
|
||||||
// Get the orders from the the Exchange calldata in the 0x transaction
|
// Get the orders from the the Exchange calldata in the 0x transaction
|
||||||
LibOrder.Order[] memory orders = decodeFillDataOrders(transaction.data);
|
LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data);
|
||||||
|
|
||||||
// No approval is required for non-fill methods
|
// No approval is required for non-fill methods
|
||||||
if (orders.length > 0) {
|
if (orders.length > 0) {
|
||||||
@@ -74,6 +74,57 @@ contract MixinCoordinatorApprovalVerifier is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Decodes the orders from Exchange calldata representing any fill method.
|
||||||
|
/// @param data Exchange calldata representing a fill method.
|
||||||
|
/// @return The orders from the Exchange calldata.
|
||||||
|
function decodeOrdersFromFillData(bytes memory data)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (LibOrder.Order[] memory orders)
|
||||||
|
{
|
||||||
|
bytes4 selector = data.readBytes4(0);
|
||||||
|
if (
|
||||||
|
selector == FILL_ORDER_SELECTOR ||
|
||||||
|
selector == FILL_ORDER_NO_THROW_SELECTOR ||
|
||||||
|
selector == FILL_OR_KILL_ORDER_SELECTOR
|
||||||
|
) {
|
||||||
|
// Decode single order
|
||||||
|
(LibOrder.Order memory order) = abi.decode(
|
||||||
|
data.slice(4, data.length),
|
||||||
|
(LibOrder.Order)
|
||||||
|
);
|
||||||
|
orders = new LibOrder.Order[](1);
|
||||||
|
orders[0] = order;
|
||||||
|
} else if (
|
||||||
|
selector == BATCH_FILL_ORDERS_SELECTOR ||
|
||||||
|
selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
||||||
|
selector == MARKET_BUY_ORDERS_SELECTOR ||
|
||||||
|
selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
selector == MARKET_SELL_ORDERS_SELECTOR ||
|
||||||
|
selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||||
|
) {
|
||||||
|
// Decode all orders
|
||||||
|
// solhint-disable indent
|
||||||
|
(orders) = abi.decode(
|
||||||
|
data.slice(4, data.length),
|
||||||
|
(LibOrder.Order[])
|
||||||
|
);
|
||||||
|
} else if (selector == MATCH_ORDERS_SELECTOR) {
|
||||||
|
// Decode left and right orders
|
||||||
|
(LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(
|
||||||
|
data.slice(4, data.length),
|
||||||
|
(LibOrder.Order, LibOrder.Order)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create array of orders
|
||||||
|
orders = new LibOrder.Order[](2);
|
||||||
|
orders[0] = leftOrder;
|
||||||
|
orders[1] = rightOrder;
|
||||||
|
}
|
||||||
|
return orders;
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
|
/// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
|
||||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
||||||
/// @param orders Array of order structs containing order specifications.
|
/// @param orders Array of order structs containing order specifications.
|
||||||
@@ -89,7 +140,7 @@ contract MixinCoordinatorApprovalVerifier is
|
|||||||
uint256[] memory approvalExpirationTimeSeconds,
|
uint256[] memory approvalExpirationTimeSeconds,
|
||||||
bytes[] memory approvalSignatures
|
bytes[] memory approvalSignatures
|
||||||
)
|
)
|
||||||
public
|
internal
|
||||||
view
|
view
|
||||||
{
|
{
|
||||||
// Verify that Ethereum tx signer is the same as the approved txOrigin
|
// Verify that Ethereum tx signer is the same as the approved txOrigin
|
||||||
@@ -149,55 +200,4 @@ contract MixinCoordinatorApprovalVerifier is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Decodes the orders from Exchange calldata representing any fill method.
|
|
||||||
/// @param data Exchange calldata representing a fill method.
|
|
||||||
/// @return The orders from the Exchange calldata.
|
|
||||||
function decodeFillDataOrders(bytes memory data)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (LibOrder.Order[] memory orders)
|
|
||||||
{
|
|
||||||
bytes4 selector = data.readBytes4(0);
|
|
||||||
if (
|
|
||||||
selector == FILL_ORDER_SELECTOR ||
|
|
||||||
selector == FILL_ORDER_NO_THROW_SELECTOR ||
|
|
||||||
selector == FILL_OR_KILL_ORDER_SELECTOR
|
|
||||||
) {
|
|
||||||
// Decode single order
|
|
||||||
(LibOrder.Order memory order) = abi.decode(
|
|
||||||
data.slice(4, data.length),
|
|
||||||
(LibOrder.Order)
|
|
||||||
);
|
|
||||||
orders = new LibOrder.Order[](1);
|
|
||||||
orders[0] = order;
|
|
||||||
} else if (
|
|
||||||
selector == BATCH_FILL_ORDERS_SELECTOR ||
|
|
||||||
selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
|
||||||
selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
|
||||||
selector == MARKET_BUY_ORDERS_SELECTOR ||
|
|
||||||
selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
|
||||||
selector == MARKET_SELL_ORDERS_SELECTOR ||
|
|
||||||
selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
|
||||||
) {
|
|
||||||
// Decode all orders
|
|
||||||
// solhint-disable indent
|
|
||||||
(orders) = abi.decode(
|
|
||||||
data.slice(4, data.length),
|
|
||||||
(LibOrder.Order[])
|
|
||||||
);
|
|
||||||
} else if (selector == MATCH_ORDERS_SELECTOR) {
|
|
||||||
// Decode left and right orders
|
|
||||||
(LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(
|
|
||||||
data.slice(4, data.length),
|
|
||||||
(LibOrder.Order, LibOrder.Order)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create array of orders
|
|
||||||
orders = new LibOrder.Order[](2);
|
|
||||||
orders[0] = leftOrder;
|
|
||||||
orders[1] = rightOrder;
|
|
||||||
}
|
|
||||||
return orders;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -42,21 +42,11 @@ contract ICoordinatorApprovalVerifier {
|
|||||||
public
|
public
|
||||||
view;
|
view;
|
||||||
|
|
||||||
/// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
|
/// @dev Decodes the orders from Exchange calldata representing any fill method.
|
||||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
/// @param data Exchange calldata representing a fill method.
|
||||||
/// @param orders Array of order structs containing order specifications.
|
/// @return The orders from the Exchange calldata.
|
||||||
/// @param txOrigin Required signer of Ethereum transaction calling this function.
|
function decodeOrdersFromFillData(bytes memory data)
|
||||||
/// @param transactionSignature Proof that the transaction has been signed by the signer.
|
|
||||||
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
|
|
||||||
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
|
|
||||||
function assertValidTransactionOrdersApproval(
|
|
||||||
LibZeroExTransaction.ZeroExTransaction memory transaction,
|
|
||||||
LibOrder.Order[] memory orders,
|
|
||||||
address txOrigin,
|
|
||||||
bytes memory transactionSignature,
|
|
||||||
uint256[] memory approvalExpirationTimeSeconds,
|
|
||||||
bytes[] memory approvalSignatures
|
|
||||||
)
|
|
||||||
public
|
public
|
||||||
view;
|
pure
|
||||||
|
returns (LibOrder.Order[] memory orders);
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.5;
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental "ABIEncoderV2";
|
||||||
|
|
||||||
import "./LibEIP712Domain.sol";
|
import "./LibEIP712Domain.sol";
|
||||||
|
|
||||||
@@ -37,16 +38,16 @@ contract LibCoordinatorApproval is
|
|||||||
|
|
||||||
struct CoordinatorApproval {
|
struct CoordinatorApproval {
|
||||||
address txOrigin; // Required signer of Ethereum transaction that is submitting approval.
|
address txOrigin; // Required signer of Ethereum transaction that is submitting approval.
|
||||||
bytes32 transactionHash; // EIP712 hash of the transaction, using the domain separator of this contract.
|
bytes32 transactionHash; // EIP712 hash of the transaction.
|
||||||
bytes transactionSignature; // Signature of the 0x transaction.
|
bytes transactionSignature; // Signature of the 0x transaction.
|
||||||
uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the signature expires.
|
uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the approval expires.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.
|
/// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.
|
||||||
/// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.
|
/// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.
|
||||||
/// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.
|
/// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.
|
||||||
function getCoordinatorApprovalHash(CoordinatorApproval memory approval)
|
function getCoordinatorApprovalHash(CoordinatorApproval memory approval)
|
||||||
internal
|
public
|
||||||
view
|
view
|
||||||
returns (bytes32 approvalHash)
|
returns (bytes32 approvalHash)
|
||||||
{
|
{
|
||||||
@@ -71,9 +72,10 @@ contract LibCoordinatorApproval is
|
|||||||
// Assembly for more efficiently computing:
|
// Assembly for more efficiently computing:
|
||||||
// keccak256(abi.encodePacked(
|
// keccak256(abi.encodePacked(
|
||||||
// EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,
|
// EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,
|
||||||
|
// approval.txOrigin,
|
||||||
// approval.transactionHash,
|
// approval.transactionHash,
|
||||||
// keccak256(approval.transactionSignature)
|
// keccak256(approval.transactionSignature)
|
||||||
// approval.expiration,
|
// approval.approvalExpirationTimeSeconds,
|
||||||
// ));
|
// ));
|
||||||
|
|
||||||
assembly {
|
assembly {
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.5;
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental "ABIEncoderV2";
|
||||||
|
|
||||||
import "./LibEIP712Domain.sol";
|
import "./LibEIP712Domain.sol";
|
||||||
|
|
||||||
@@ -40,11 +41,11 @@ contract LibZeroExTransaction is
|
|||||||
bytes data; // AbiV2 encoded calldata.
|
bytes data; // AbiV2 encoded calldata.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of this contract.
|
/// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.
|
||||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
||||||
/// @return EIP712 hash of the transaction with the domain separator of this contract.
|
/// @return EIP712 hash of the transaction with the domain separator of this contract.
|
||||||
function getTransactionHash(ZeroExTransaction memory transaction)
|
function getTransactionHash(ZeroExTransaction memory transaction)
|
||||||
internal
|
public
|
||||||
view
|
view
|
||||||
returns (bytes32 transactionHash)
|
returns (bytes32 transactionHash)
|
||||||
{
|
{
|
||||||
|
@@ -26,11 +26,21 @@ import "../interfaces/ICoordinatorApprovalVerifier.sol";
|
|||||||
contract MCoordinatorApprovalVerifier is
|
contract MCoordinatorApprovalVerifier is
|
||||||
ICoordinatorApprovalVerifier
|
ICoordinatorApprovalVerifier
|
||||||
{
|
{
|
||||||
/// @dev Decodes the orders from Exchange calldata representing any fill method.
|
/// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
|
||||||
/// @param data Exchange calldata representing a fill method.
|
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
||||||
/// @return The orders from the Exchange calldata.
|
/// @param orders Array of order structs containing order specifications.
|
||||||
function decodeFillDataOrders(bytes memory data)
|
/// @param txOrigin Required signer of Ethereum transaction calling this function.
|
||||||
|
/// @param transactionSignature Proof that the transaction has been signed by the signer.
|
||||||
|
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
|
||||||
|
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
|
||||||
|
function assertValidTransactionOrdersApproval(
|
||||||
|
LibZeroExTransaction.ZeroExTransaction memory transaction,
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
address txOrigin,
|
||||||
|
bytes memory transactionSignature,
|
||||||
|
uint256[] memory approvalExpirationTimeSeconds,
|
||||||
|
bytes[] memory approvalSignatures
|
||||||
|
)
|
||||||
internal
|
internal
|
||||||
pure
|
view;
|
||||||
returns (LibOrder.Order[] memory orders);
|
|
||||||
}
|
}
|
||||||
|
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2018 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.5;
|
|
||||||
pragma experimental "ABIEncoderV2";
|
|
||||||
|
|
||||||
import "../src/libs/LibConstants.sol";
|
|
||||||
import "../src/libs/LibCoordinatorApproval.sol";
|
|
||||||
import "../src/libs/LibZeroExTransaction.sol";
|
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable no-empty-blocks
|
|
||||||
contract TestLibs is
|
|
||||||
LibConstants,
|
|
||||||
LibCoordinatorApproval,
|
|
||||||
LibZeroExTransaction
|
|
||||||
{
|
|
||||||
constructor (address _exchange)
|
|
||||||
public
|
|
||||||
LibConstants(_exchange)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.
|
|
||||||
/// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.
|
|
||||||
/// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.
|
|
||||||
function publicGetCoordinatorApprovalHash(CoordinatorApproval memory approval)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (bytes32 approvalHash)
|
|
||||||
{
|
|
||||||
approvalHash = getCoordinatorApprovalHash(approval);
|
|
||||||
return approvalHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.
|
|
||||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
|
||||||
/// @return EIP712 hash of the transaction with the domain separator of the Exchange contract.
|
|
||||||
function publicGetTransactionHash(ZeroExTransaction memory transaction)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (bytes32 transactionHash)
|
|
||||||
{
|
|
||||||
transactionHash = getTransactionHash(transaction);
|
|
||||||
return transactionHash;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-coordinator",
|
"name": "@0x/contracts-coordinator",
|
||||||
"version": "1.1.0",
|
"version": "2.0.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
"coverage:report:text": "istanbul report text",
|
"coverage:report:text": "istanbul report text",
|
||||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry|TestLibs|TestMixins).json",
|
"abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -46,12 +47,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^2.0.8",
|
"@0x/abi-gen": "^2.1.1",
|
||||||
"@0x/contracts-gen": "^1.0.7",
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
"@0x/contracts-test-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
"@0x/dev-utils": "^2.2.0",
|
"@0x/dev-utils": "^2.2.4",
|
||||||
"@0x/sol-compiler": "^3.1.5",
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
"@0x/tslint-config": "^3.0.0",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@@ -67,18 +68,18 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.4",
|
"@0x/base-contract": "^5.1.1",
|
||||||
"@0x/contracts-asset-proxy": "^2.1.0",
|
"@0x/contracts-asset-proxy": "^2.2.1",
|
||||||
"@0x/contracts-erc20": "^2.1.0",
|
"@0x/contracts-erc20": "^2.2.7",
|
||||||
"@0x/contracts-exchange": "1.0.2",
|
"@0x/contracts-exchange": "^2.1.7",
|
||||||
"@0x/contracts-exchange-libs": "^2.1.0",
|
"@0x/contracts-exchange-libs": "^3.0.1",
|
||||||
"@0x/contracts-utils": "^3.1.0",
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
"@0x/order-utils": "^7.1.1",
|
"@0x/order-utils": "^8.2.1",
|
||||||
"@0x/types": "^2.2.1",
|
"@0x/types": "^2.4.0",
|
||||||
"@0x/typescript-typings": "^4.2.1",
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
"@0x/utils": "^4.3.0",
|
"@0x/utils": "^4.4.0",
|
||||||
"@0x/web3-wrapper": "^6.0.4",
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
"ethereum-types": "^2.1.1",
|
"ethereum-types": "^2.1.3",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@@ -7,11 +7,7 @@ import { ContractArtifact } from 'ethereum-types';
|
|||||||
|
|
||||||
import * as Coordinator from '../generated-artifacts/Coordinator.json';
|
import * as Coordinator from '../generated-artifacts/Coordinator.json';
|
||||||
import * as CoordinatorRegistry from '../generated-artifacts/CoordinatorRegistry.json';
|
import * as CoordinatorRegistry from '../generated-artifacts/CoordinatorRegistry.json';
|
||||||
import * as TestLibs from '../generated-artifacts/TestLibs.json';
|
|
||||||
import * as TestMixins from '../generated-artifacts/TestMixins.json';
|
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
Coordinator: Coordinator as ContractArtifact,
|
Coordinator: Coordinator as ContractArtifact,
|
||||||
CoordinatorRegistry: CoordinatorRegistry as ContractArtifact,
|
CoordinatorRegistry: CoordinatorRegistry as ContractArtifact,
|
||||||
TestLibs: TestLibs as ContractArtifact,
|
|
||||||
TestMixins: TestMixins as ContractArtifact,
|
|
||||||
};
|
};
|
||||||
|
@@ -5,5 +5,3 @@
|
|||||||
*/
|
*/
|
||||||
export * from '../generated-wrappers/coordinator';
|
export * from '../generated-wrappers/coordinator';
|
||||||
export * from '../generated-wrappers/coordinator_registry';
|
export * from '../generated-wrappers/coordinator_registry';
|
||||||
export * from '../generated-wrappers/test_libs';
|
|
||||||
export * from '../generated-wrappers/test_mixins';
|
|
||||||
|
@@ -435,7 +435,7 @@ describe('Coordinator tests', () => {
|
|||||||
describe('cancels', () => {
|
describe('cancels', () => {
|
||||||
it('cancelOrder call should be successful without an approval', async () => {
|
it('cancelOrder call should be successful without an approval', async () => {
|
||||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders);
|
||||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||||
|
@@ -4,14 +4,14 @@ import { transactionHashUtils } from '@0x/order-utils';
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
|
||||||
import { artifacts, hashUtils, TestLibsContract } from '../src';
|
import { artifacts, CoordinatorContract, hashUtils } from '../src';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
|
||||||
describe('Libs tests', () => {
|
describe('Libs tests', () => {
|
||||||
let testLibs: TestLibsContract;
|
let coordinatorContract: CoordinatorContract;
|
||||||
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
|
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@@ -21,8 +21,8 @@ describe('Libs tests', () => {
|
|||||||
await blockchainLifecycle.revertAsync();
|
await blockchainLifecycle.revertAsync();
|
||||||
});
|
});
|
||||||
before(async () => {
|
before(async () => {
|
||||||
testLibs = await TestLibsContract.deployFrom0xArtifactAsync(
|
coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.TestLibs,
|
artifacts.Coordinator,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
exchangeAddress,
|
exchangeAddress,
|
||||||
@@ -44,7 +44,7 @@ describe('Libs tests', () => {
|
|||||||
data: '0x1234',
|
data: '0x1234',
|
||||||
};
|
};
|
||||||
const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx);
|
const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx);
|
||||||
const txHash = await testLibs.publicGetTransactionHash.callAsync(tx);
|
const txHash = await coordinatorContract.getTransactionHash.callAsync(tx);
|
||||||
expect(expectedTxHash).to.eq(txHash);
|
expect(expectedTxHash).to.eq(txHash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -68,11 +68,11 @@ describe('Libs tests', () => {
|
|||||||
};
|
};
|
||||||
const expectedApprovalHash = hashUtils.getApprovalHashHex(
|
const expectedApprovalHash = hashUtils.getApprovalHashHex(
|
||||||
signedTx,
|
signedTx,
|
||||||
testLibs.address,
|
coordinatorContract.address,
|
||||||
txOrigin,
|
txOrigin,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
const approvalHash = await testLibs.publicGetCoordinatorApprovalHash.callAsync(approval);
|
const approvalHash = await coordinatorContract.getCoordinatorApprovalHash.callAsync(approval);
|
||||||
expect(expectedApprovalHash).to.eq(approvalHash);
|
expect(expectedApprovalHash).to.eq(approvalHash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -16,7 +16,7 @@ import { BigNumber } from '@0x/utils';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import { ApprovalFactory, artifacts, constants, exchangeDataEncoder, TestMixinsContract } from '../src';
|
import { ApprovalFactory, artifacts, constants, CoordinatorContract, exchangeDataEncoder } from '../src';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -26,7 +26,7 @@ describe('Mixins tests', () => {
|
|||||||
let transactionSignerAddress: string;
|
let transactionSignerAddress: string;
|
||||||
let approvalSignerAddress1: string;
|
let approvalSignerAddress1: string;
|
||||||
let approvalSignerAddress2: string;
|
let approvalSignerAddress2: string;
|
||||||
let mixins: TestMixinsContract;
|
let mixins: CoordinatorContract;
|
||||||
let transactionFactory: TransactionFactory;
|
let transactionFactory: TransactionFactory;
|
||||||
let approvalFactory1: ApprovalFactory;
|
let approvalFactory1: ApprovalFactory;
|
||||||
let approvalFactory2: ApprovalFactory;
|
let approvalFactory2: ApprovalFactory;
|
||||||
@@ -40,8 +40,8 @@ describe('Mixins tests', () => {
|
|||||||
await blockchainLifecycle.revertAsync();
|
await blockchainLifecycle.revertAsync();
|
||||||
});
|
});
|
||||||
before(async () => {
|
before(async () => {
|
||||||
mixins = await TestMixinsContract.deployFrom0xArtifactAsync(
|
mixins = await CoordinatorContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.TestMixins,
|
artifacts.Coordinator,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
exchangeAddress,
|
exchangeAddress,
|
||||||
@@ -135,6 +135,70 @@ describe('Mixins tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('decodeOrdersFromFillData', () => {
|
||||||
|
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
||||||
|
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||||
|
const orders = [defaultOrder];
|
||||||
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
|
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||||
|
const decodedSignedOrders = decodedOrders.map(order => ({
|
||||||
|
...order,
|
||||||
|
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||||
|
signature: devConstants.NULL_BYTES,
|
||||||
|
}));
|
||||||
|
expect(orders).to.deep.eq(decodedSignedOrders);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const fnName of constants.BATCH_FILL_FN_NAMES) {
|
||||||
|
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||||
|
const orders = [defaultOrder, defaultOrder];
|
||||||
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
|
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||||
|
const decodedSignedOrders = decodedOrders.map(order => ({
|
||||||
|
...order,
|
||||||
|
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||||
|
signature: devConstants.NULL_BYTES,
|
||||||
|
}));
|
||||||
|
expect(orders).to.deep.eq(decodedSignedOrders);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const fnName of constants.MARKET_FILL_FN_NAMES) {
|
||||||
|
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||||
|
const orders = [defaultOrder, defaultOrder];
|
||||||
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
|
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||||
|
const decodedSignedOrders = decodedOrders.map(order => ({
|
||||||
|
...order,
|
||||||
|
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||||
|
signature: devConstants.NULL_BYTES,
|
||||||
|
}));
|
||||||
|
expect(orders).to.deep.eq(decodedSignedOrders);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const fnName of [constants.CANCEL_ORDER, constants.BATCH_CANCEL_ORDERS, constants.CANCEL_ORDERS_UP_TO]) {
|
||||||
|
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||||
|
const orders = [defaultOrder, defaultOrder];
|
||||||
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
|
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||||
|
const emptyArray: any[] = [];
|
||||||
|
expect(emptyArray).to.deep.eq(decodedOrders);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
it('should decode an empty array for invalid data', async () => {
|
||||||
|
const data = '0x0123456789';
|
||||||
|
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||||
|
const emptyArray: any[] = [];
|
||||||
|
expect(emptyArray).to.deep.eq(decodedOrders);
|
||||||
|
});
|
||||||
|
it('should revert if data is less than 4 bytes long', async () => {
|
||||||
|
const data = '0x010203';
|
||||||
|
await expectContractCallFailedAsync(
|
||||||
|
mixins.decodeOrdersFromFillData.callAsync(data),
|
||||||
|
RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Single order approvals', () => {
|
describe('Single order approvals', () => {
|
||||||
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
||||||
it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
|
it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||||
@@ -148,15 +212,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -181,15 +236,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -203,15 +249,6 @@ describe('Mixins tests', () => {
|
|||||||
const orders = [defaultOrder];
|
const orders = [defaultOrder];
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
const transaction = transactionFactory.newSignedTransaction(data);
|
const transaction = transactionFactory.newSignedTransaction(data);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
approvalSignerAddress1,
|
|
||||||
transaction.signature,
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
approvalSignerAddress1,
|
approvalSignerAddress1,
|
||||||
@@ -234,15 +271,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
approvalSignerAddress1,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
approvalSignerAddress1,
|
approvalSignerAddress1,
|
||||||
@@ -256,15 +284,6 @@ describe('Mixins tests', () => {
|
|||||||
const orders = [defaultOrder];
|
const orders = [defaultOrder];
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
const transaction = transactionFactory.newSignedTransaction(data);
|
const transaction = transactionFactory.newSignedTransaction(data);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
approvalSignerAddress1,
|
|
||||||
transaction.signature,
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
approvalSignerAddress1,
|
approvalSignerAddress1,
|
||||||
@@ -288,18 +307,6 @@ describe('Mixins tests', () => {
|
|||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidApprovalSignature,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -323,18 +330,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
),
|
|
||||||
RevertReason.ApprovalExpired,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -358,18 +353,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: approvalSignerAddress2 },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidOrigin,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -401,15 +384,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -433,15 +407,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -458,15 +423,6 @@ describe('Mixins tests', () => {
|
|||||||
}));
|
}));
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
const transaction = transactionFactory.newSignedTransaction(data);
|
const transaction = transactionFactory.newSignedTransaction(data);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -487,15 +443,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -521,15 +468,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
|
|
||||||
[approval1.signature, approval2.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
@@ -543,15 +481,6 @@ describe('Mixins tests', () => {
|
|||||||
const orders = [defaultOrder, defaultOrder];
|
const orders = [defaultOrder, defaultOrder];
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
const transaction = transactionFactory.newSignedTransaction(data);
|
const transaction = transactionFactory.newSignedTransaction(data);
|
||||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
approvalSignerAddress1,
|
|
||||||
transaction.signature,
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
);
|
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
approvalSignerAddress1,
|
approvalSignerAddress1,
|
||||||
@@ -572,18 +501,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval2.signature],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidOrigin,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -600,18 +517,6 @@ describe('Mixins tests', () => {
|
|||||||
const orders = [defaultOrder, defaultOrder];
|
const orders = [defaultOrder, defaultOrder];
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||||
const transaction = transactionFactory.newSignedTransaction(data);
|
const transaction = transactionFactory.newSignedTransaction(data);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidApprovalSignature,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -636,18 +541,6 @@ describe('Mixins tests', () => {
|
|||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidApprovalSignature,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -677,18 +570,6 @@ describe('Mixins tests', () => {
|
|||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
|
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
|
|
||||||
[approval1.signature, approvalSignature2],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidApprovalSignature,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -713,18 +594,6 @@ describe('Mixins tests', () => {
|
|||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
|
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
approvalSignerAddress1,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approvalSignature2],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidApprovalSignature,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -754,18 +623,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds2,
|
approvalExpirationTimeSeconds2,
|
||||||
);
|
);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2],
|
|
||||||
[approval1.signature, approval2.signature],
|
|
||||||
{ from: transactionSignerAddress },
|
|
||||||
),
|
|
||||||
RevertReason.ApprovalExpired,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -789,18 +646,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
approvalSignerAddress1,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval2.signature],
|
|
||||||
{ from: approvalSignerAddress1 },
|
|
||||||
),
|
|
||||||
RevertReason.ApprovalExpired,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -824,18 +669,6 @@ describe('Mixins tests', () => {
|
|||||||
transactionSignerAddress,
|
transactionSignerAddress,
|
||||||
approvalExpirationTimeSeconds,
|
approvalExpirationTimeSeconds,
|
||||||
);
|
);
|
||||||
expectContractCallFailedAsync(
|
|
||||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
|
||||||
transaction,
|
|
||||||
orders,
|
|
||||||
transactionSignerAddress,
|
|
||||||
transaction.signature,
|
|
||||||
[approvalExpirationTimeSeconds],
|
|
||||||
[approval1.signature],
|
|
||||||
{ from: approvalSignerAddress2 },
|
|
||||||
),
|
|
||||||
RevertReason.InvalidOrigin,
|
|
||||||
);
|
|
||||||
expectContractCallFailedAsync(
|
expectContractCallFailedAsync(
|
||||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
@@ -851,9 +684,9 @@ describe('Mixins tests', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
describe('cancels', () => {
|
describe('cancels', () => {
|
||||||
it('should allow the tx signer to call `cancelOrders` without approval', async () => {
|
it('should allow the tx signer to call `cancelOrder` without approval', async () => {
|
||||||
const orders = [defaultOrder];
|
const orders = [defaultOrder];
|
||||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS, orders);
|
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders);
|
||||||
const transaction = transactionFactory.newSignedTransaction(data);
|
const transaction = transactionFactory.newSignedTransaction(data);
|
||||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||||
transaction,
|
transaction,
|
||||||
|
@@ -5,7 +5,7 @@ export const constants = {
|
|||||||
BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'],
|
BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'],
|
||||||
MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'],
|
MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'],
|
||||||
MATCH_ORDERS: 'matchOrders',
|
MATCH_ORDERS: 'matchOrders',
|
||||||
CANCEL_ORDERS: 'cancelOrders',
|
CANCEL_ORDER: 'cancelOrder',
|
||||||
BATCH_CANCEL_ORDERS: 'batchCancelOrders',
|
BATCH_CANCEL_ORDERS: 'batchCancelOrders',
|
||||||
CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo',
|
CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo',
|
||||||
TIME_BUFFER: new BigNumber(1000),
|
TIME_BUFFER: new BigNumber(1000),
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { LogDecoder, txDefaults } from '@0x/contracts-test-utils';
|
import { LogDecoder, txDefaults } from '@0x/contracts-test-utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
|
import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
import { artifacts, CoordinatorRegistryContract } from '../../src';
|
import { artifacts, CoordinatorRegistryContract } from '../../src';
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ export class CoordinatorRegistryWrapper {
|
|||||||
this._provider,
|
this._provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
);
|
);
|
||||||
if (_.isUndefined(this._coordinatorRegistryContract)) {
|
if (this._coordinatorRegistryContract === undefined) {
|
||||||
throw new Error(`Failed to deploy Coordinator Registry contract.`);
|
throw new Error(`Failed to deploy Coordinator Registry contract.`);
|
||||||
}
|
}
|
||||||
return this._coordinatorRegistryContract;
|
return this._coordinatorRegistryContract;
|
||||||
@@ -56,7 +55,7 @@ export class CoordinatorRegistryWrapper {
|
|||||||
return coordinatorEndpoint;
|
return coordinatorEndpoint;
|
||||||
}
|
}
|
||||||
private _assertCoordinatorRegistryDeployed(): void {
|
private _assertCoordinatorRegistryDeployed(): void {
|
||||||
if (_.isUndefined(this._coordinatorRegistryContract)) {
|
if (this._coordinatorRegistryContract === undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The Coordinator Registry contract was not deployed through the CoordinatorRegistryWrapper. Call `deployCoordinatorRegistryAsync` to deploy.',
|
'The Coordinator Registry contract was not deployed through the CoordinatorRegistryWrapper. Call `deployCoordinatorRegistryAsync` to deploy.',
|
||||||
);
|
);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { artifacts, IExchangeContract } from '@0x/contracts-exchange';
|
import { IExchangeContract } from '@0x/contracts-exchange';
|
||||||
import { constants as devConstants, provider } from '@0x/contracts-test-utils';
|
import { constants as devConstants, provider } from '@0x/contracts-test-utils';
|
||||||
import { SignedOrder } from '@0x/types';
|
import { SignedOrder } from '@0x/types';
|
||||||
|
|
||||||
@@ -6,11 +6,7 @@ import { constants } from './index';
|
|||||||
|
|
||||||
export const exchangeDataEncoder = {
|
export const exchangeDataEncoder = {
|
||||||
encodeOrdersToExchangeData(fnName: string, orders: SignedOrder[]): string {
|
encodeOrdersToExchangeData(fnName: string, orders: SignedOrder[]): string {
|
||||||
const exchangeInstance = new IExchangeContract(
|
const exchangeInstance = new IExchangeContract(devConstants.NULL_ADDRESS, provider);
|
||||||
artifacts.IExchange.compilerOutput.abi,
|
|
||||||
devConstants.NULL_ADDRESS,
|
|
||||||
provider,
|
|
||||||
);
|
|
||||||
let data;
|
let data;
|
||||||
if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) {
|
if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) {
|
||||||
data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
|
data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
|
||||||
@@ -37,7 +33,7 @@ export const exchangeDataEncoder = {
|
|||||||
orders[0].signature,
|
orders[0].signature,
|
||||||
orders[1].signature,
|
orders[1].signature,
|
||||||
);
|
);
|
||||||
} else if (fnName === constants.CANCEL_ORDERS) {
|
} else if (fnName === constants.CANCEL_ORDER) {
|
||||||
data = exchangeInstance.cancelOrder.getABIEncodedTransactionData(orders[0]);
|
data = exchangeInstance.cancelOrder.getABIEncodedTransactionData(orders[0]);
|
||||||
} else if (fnName === constants.BATCH_CANCEL_ORDERS) {
|
} else if (fnName === constants.BATCH_CANCEL_ORDERS) {
|
||||||
data = exchangeInstance.batchCancelOrders.getABIEncodedTransactionData(orders);
|
data = exchangeInstance.batchCancelOrders.getABIEncodedTransactionData(orders);
|
||||||
|
@@ -2,11 +2,6 @@
|
|||||||
"extends": "../../tsconfig",
|
"extends": "../../tsconfig",
|
||||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
"files": [
|
"files": ["generated-artifacts/Coordinator.json", "generated-artifacts/CoordinatorRegistry.json"],
|
||||||
"generated-artifacts/Coordinator.json",
|
|
||||||
"generated-artifacts/CoordinatorRegistry.json",
|
|
||||||
"generated-artifacts/TestLibs.json",
|
|
||||||
"generated-artifacts/TestMixins.json"
|
|
||||||
],
|
|
||||||
"exclude": ["./deploy/solc/solc_bin"]
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
}
|
}
|
||||||
|
49
contracts/dev-utils/CHANGELOG.json
Normal file
49
contracts/dev-utils/CHANGELOG.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "0.0.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1563006338,
|
||||||
|
"version": "0.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "0.0.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Create dev-utils package",
|
||||||
|
"pr": 1848
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `LibAssetData` and `LibTransactionDecoder` contracts",
|
||||||
|
"pr": 1848
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Refactor `LibAssetData` to only check 0x-specific allowances",
|
||||||
|
"pr": 1848
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Refactor `LibAssetData` balance/allowance checks to never revert",
|
||||||
|
"pr": 1848
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount`",
|
||||||
|
"pr": 1848
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add support for StaticCallProxy",
|
||||||
|
"pr": 1863
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
23
contracts/dev-utils/CHANGELOG.md
Normal file
23
contracts/dev-utils/CHANGELOG.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!--
|
||||||
|
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||||
|
Edit the package's CHANGELOG.json file only.
|
||||||
|
-->
|
||||||
|
|
||||||
|
CHANGELOG
|
||||||
|
|
||||||
|
## v0.0.3 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v0.0.2 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v0.0.1 - _Invalid date_
|
||||||
|
|
||||||
|
* Create dev-utils package (#1848)
|
||||||
|
* Add `LibAssetData` and `LibTransactionDecoder` contracts (#1848)
|
||||||
|
* Refactor `LibAssetData` to only check 0x-specific allowances (#1848)
|
||||||
|
* Refactor `LibAssetData` balance/allowance checks to never revert (#1848)
|
||||||
|
* Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848)
|
||||||
|
* Add support for StaticCallProxy (#1863)
|
1
contracts/dev-utils/DEPLOYS.json
Normal file
1
contracts/dev-utils/DEPLOYS.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[]
|
73
contracts/dev-utils/README.md
Normal file
73
contracts/dev-utils/README.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
## Dev-Utils
|
||||||
|
|
||||||
|
This package implements various utilities for developers. For example, the `DevUtils` contract can query batches of balances or allowances given some `assetData`, can validate batches of orders, and can decode 0x-specific calldata. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
**Install**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @0x/contracts-dev-utils --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bug bounty
|
||||||
|
|
||||||
|
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||||
|
|
||||||
|
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||||
|
|
||||||
|
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||||
|
|
||||||
|
### Install Dependencies
|
||||||
|
|
||||||
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn config set workspaces-experimental true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-extensions yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-extensions yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Testing options
|
||||||
|
|
||||||
|
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
32
contracts/dev-utils/compiler.json
Normal file
32
contracts/dev-utils/compiler.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"useDockerisedSolc": false,
|
||||||
|
"isOfflineMode": false,
|
||||||
|
"compilerSettings": {
|
||||||
|
"evmVersion": "constantinople",
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000,
|
||||||
|
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"devdoc",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contracts": [
|
||||||
|
"src/DevUtils.sol",
|
||||||
|
"src/LibAssetData.sol",
|
||||||
|
"src/LibTransactionDecoder.sol",
|
||||||
|
"src/EthBalanceChecker.sol"
|
||||||
|
]
|
||||||
|
}
|
@@ -17,21 +17,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.5;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental "ABIEncoderV2";
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../src/libs/LibConstants.sol";
|
import "./OrderValidationUtils.sol";
|
||||||
import "../src/MixinSignatureValidator.sol";
|
import "./LibTransactionDecoder.sol";
|
||||||
import "../src/MixinCoordinatorApprovalVerifier.sol";
|
import "./EthBalanceChecker.sol";
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable no-empty-blocks
|
// solhint-disable no-empty-blocks
|
||||||
contract TestMixins is
|
contract DevUtils is
|
||||||
LibConstants,
|
OrderValidationUtils,
|
||||||
MixinSignatureValidator,
|
LibTransactionDecoder,
|
||||||
MixinCoordinatorApprovalVerifier
|
EthBalanceChecker
|
||||||
{
|
{
|
||||||
constructor (address _exchange)
|
constructor (address _exchange, bytes memory _zrxAssetData)
|
||||||
public
|
public
|
||||||
LibConstants(_exchange)
|
OrderValidationUtils(_exchange, _zrxAssetData)
|
||||||
{}
|
{}
|
||||||
}
|
}
|
39
contracts/dev-utils/contracts/src/EthBalanceChecker.sol
Normal file
39
contracts/dev-utils/contracts/src/EthBalanceChecker.sol
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
|
||||||
|
contract EthBalanceChecker {
|
||||||
|
|
||||||
|
/// @dev Batch fetches ETH balances
|
||||||
|
/// @param addresses Array of addresses.
|
||||||
|
/// @return Array of ETH balances.
|
||||||
|
function getEthBalances(address[] memory addresses)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory)
|
||||||
|
{
|
||||||
|
uint256[] memory balances = new uint256[](addresses.length);
|
||||||
|
for (uint256 i = 0; i != addresses.length; i++) {
|
||||||
|
balances[i] = addresses[i].balance;
|
||||||
|
}
|
||||||
|
return balances;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
541
contracts/dev-utils/contracts/src/LibAssetData.sol
Normal file
541
contracts/dev-utils/contracts/src/LibAssetData.sol
Normal file
@@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
|
import "@0x/contracts-asset-proxy/contracts/src/libs/LibAssetProxyIds.sol";
|
||||||
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract LibAssetData is
|
||||||
|
LibAssetProxyIds
|
||||||
|
{
|
||||||
|
// 2^256 - 1
|
||||||
|
uint256 constant internal _MAX_UINT256 = uint256(-1);
|
||||||
|
|
||||||
|
// ERC20 selectors
|
||||||
|
bytes4 constant internal _ERC20_BALANCE_OF_SELECTOR = 0x70a08231;
|
||||||
|
bytes4 constant internal _ERC20_ALLOWANCE_SELECTOR = 0xdd62ed3e;
|
||||||
|
|
||||||
|
// ERC721 selectors
|
||||||
|
bytes4 constant internal _ERC721_OWNER_OF_SELECTOR = 0x6352211e;
|
||||||
|
bytes4 constant internal _ERC721_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
|
||||||
|
bytes4 constant internal _ERC721_GET_APPROVED_SELECTOR = 0x081812fc;
|
||||||
|
|
||||||
|
// ERC1155 selectors
|
||||||
|
bytes4 constant internal _ERC1155_BALANCE_OF_SELECTOR = 0x00fdd58e;
|
||||||
|
bytes4 constant internal _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
|
||||||
|
|
||||||
|
// `transferFrom` selector for all AssetProxy contracts
|
||||||
|
bytes4 constant internal _ASSET_PROXY_TRANSFER_FROM_SELECTOR = 0xa85e59e4;
|
||||||
|
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
// solhint-disable var-name-mixedcase
|
||||||
|
IExchange internal _EXCHANGE;
|
||||||
|
address internal _ERC20_PROXY_ADDRESS;
|
||||||
|
address internal _ERC721_PROXY_ADDRESS;
|
||||||
|
address internal _ERC1155_PROXY_ADDRESS;
|
||||||
|
address internal _STATIC_CALL_PROXY_ADDRESS;
|
||||||
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
|
constructor (address _exchange)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
_EXCHANGE = IExchange(_exchange);
|
||||||
|
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||||
|
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID);
|
||||||
|
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID);
|
||||||
|
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(STATIC_CALL_PROXY_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Returns the owner's balance of the assets(s) specified in
|
||||||
|
/// assetData. When the asset data contains multiple assets (eg in
|
||||||
|
/// ERC1155 or Multi-Asset), the return value indicates how many
|
||||||
|
/// complete "baskets" of those assets are owned by owner.
|
||||||
|
/// @param ownerAddress Owner of the assets specified by assetData.
|
||||||
|
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
|
||||||
|
/// @return Number of assets (or asset baskets) held by owner.
|
||||||
|
function getBalance(address ownerAddress, bytes memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256 balance)
|
||||||
|
{
|
||||||
|
// Get id of AssetProxy contract
|
||||||
|
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
if (assetProxyId == ERC20_PROXY_ID) {
|
||||||
|
// Get ERC20 token address
|
||||||
|
address tokenAddress = assetData.readAddress(16);
|
||||||
|
|
||||||
|
// Encode data for `balanceOf(ownerAddress)`
|
||||||
|
bytes memory balanceOfData = abi.encodeWithSelector(_ERC20_BALANCE_OF_SELECTOR, ownerAddress);
|
||||||
|
|
||||||
|
// Query balance
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
||||||
|
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||||
|
} else if (assetProxyId == ERC721_PROXY_ID) {
|
||||||
|
// Get ERC721 token address and id
|
||||||
|
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||||
|
|
||||||
|
// Check if id is owned by ownerAddress
|
||||||
|
balance = getERC721TokenOwner(tokenAddress, tokenId) == ownerAddress ? 1 : 0;
|
||||||
|
} else if (assetProxyId == ERC1155_PROXY_ID) {
|
||||||
|
// Get ERC1155 token address, array of ids, and array of values
|
||||||
|
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
|
||||||
|
|
||||||
|
uint256 length = tokenIds.length;
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
|
||||||
|
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||||
|
_ERC1155_BALANCE_OF_SELECTOR,
|
||||||
|
ownerAddress,
|
||||||
|
tokenIds[i]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query balance
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
||||||
|
uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||||
|
|
||||||
|
// Scale total balance down by corresponding value in assetData
|
||||||
|
uint256 scaledBalance = totalBalance / tokenValues[i];
|
||||||
|
if (scaledBalance < balance || balance == 0) {
|
||||||
|
balance = scaledBalance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (assetProxyId == STATIC_CALL_PROXY_ID) {
|
||||||
|
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
|
||||||
|
bytes memory transferFromData = abi.encodeWithSelector(
|
||||||
|
_ASSET_PROXY_TRANSFER_FROM_SELECTOR,
|
||||||
|
assetData,
|
||||||
|
address(0), // `from` address is not used
|
||||||
|
address(0), // `to` address is not used
|
||||||
|
0 // `amount` is not used
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if staticcall would be successful
|
||||||
|
(bool success,) = _STATIC_CALL_PROXY_ADDRESS.staticcall(transferFromData);
|
||||||
|
|
||||||
|
// Success means that the staticcall can be made an unlimited amount of times
|
||||||
|
balance = success ? _MAX_UINT256 : 0;
|
||||||
|
} else if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||||
|
// Get array of values and array of assetDatas
|
||||||
|
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||||
|
|
||||||
|
uint256 length = nestedAssetData.length;
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// Query balance of individual assetData
|
||||||
|
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
|
||||||
|
|
||||||
|
// Scale total balance down by corresponding value in assetData
|
||||||
|
uint256 scaledBalance = totalBalance / assetAmounts[i];
|
||||||
|
if (scaledBalance < balance || balance == 0) {
|
||||||
|
balance = scaledBalance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Balance will be 0 if assetProxyId is unknown
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls getBalance() for each element of assetData.
|
||||||
|
/// @param ownerAddress Owner of the assets specified by assetData.
|
||||||
|
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
|
||||||
|
/// @return Array of asset balances from getBalance(), with each element
|
||||||
|
/// corresponding to the same-indexed element in the assetData input.
|
||||||
|
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory balances)
|
||||||
|
{
|
||||||
|
uint256 length = assetData.length;
|
||||||
|
balances = new uint256[](length);
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
balances[i] = getBalance(ownerAddress, assetData[i]);
|
||||||
|
}
|
||||||
|
return balances;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Returns the number of asset(s) (described by assetData) that
|
||||||
|
/// the corresponding AssetProxy contract is authorized to spend. When the asset data contains
|
||||||
|
/// multiple assets (eg for Multi-Asset), the return value indicates
|
||||||
|
/// how many complete "baskets" of those assets may be spent by all of the corresponding
|
||||||
|
/// AssetProxy contracts.
|
||||||
|
/// @param ownerAddress Owner of the assets specified by assetData.
|
||||||
|
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
|
||||||
|
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
||||||
|
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256 allowance)
|
||||||
|
{
|
||||||
|
// Get id of AssetProxy contract
|
||||||
|
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||||
|
// Get array of values and array of assetDatas
|
||||||
|
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||||
|
|
||||||
|
uint256 length = nestedAssetData.length;
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// Query allowance of individual assetData
|
||||||
|
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
|
||||||
|
|
||||||
|
// Scale total allowance down by corresponding value in assetData
|
||||||
|
uint256 scaledAllowance = totalAllowance / amounts[i];
|
||||||
|
if (scaledAllowance < allowance || allowance == 0) {
|
||||||
|
allowance = scaledAllowance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allowance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assetProxyId == ERC20_PROXY_ID) {
|
||||||
|
// Get ERC20 token address
|
||||||
|
address tokenAddress = assetData.readAddress(16);
|
||||||
|
|
||||||
|
// Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)`
|
||||||
|
bytes memory allowanceData = abi.encodeWithSelector(
|
||||||
|
_ERC20_ALLOWANCE_SELECTOR,
|
||||||
|
ownerAddress,
|
||||||
|
_ERC20_PROXY_ADDRESS
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query allowance
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
|
||||||
|
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||||
|
} else if (assetProxyId == ERC721_PROXY_ID) {
|
||||||
|
// Get ERC721 token address and id
|
||||||
|
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||||
|
|
||||||
|
// Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)`
|
||||||
|
bytes memory isApprovedForAllData = abi.encodeWithSelector(
|
||||||
|
_ERC721_IS_APPROVED_FOR_ALL_SELECTOR,
|
||||||
|
ownerAddress,
|
||||||
|
_ERC721_PROXY_ADDRESS
|
||||||
|
);
|
||||||
|
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
||||||
|
|
||||||
|
// If not approved for all, call `getApproved(tokenId)`
|
||||||
|
if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
|
||||||
|
// Encode data for `getApproved(tokenId)`
|
||||||
|
bytes memory getApprovedData = abi.encodeWithSelector(_ERC721_GET_APPROVED_SELECTOR, tokenId);
|
||||||
|
(success, returnData) = tokenAddress.staticcall(getApprovedData);
|
||||||
|
|
||||||
|
// Allowance is 1 if successful and the approved address is the ERC721Proxy
|
||||||
|
allowance = success && returnData.length == 32 && returnData.readAddress(12) == _ERC721_PROXY_ADDRESS ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
|
||||||
|
allowance = _MAX_UINT256;
|
||||||
|
}
|
||||||
|
} else if (assetProxyId == ERC1155_PROXY_ID) {
|
||||||
|
// Get ERC1155 token address
|
||||||
|
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||||
|
|
||||||
|
// Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)`
|
||||||
|
bytes memory isApprovedForAllData = abi.encodeWithSelector(
|
||||||
|
_ERC1155_IS_APPROVED_FOR_ALL_SELECTOR,
|
||||||
|
ownerAddress,
|
||||||
|
_ERC1155_PROXY_ADDRESS
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query allowance
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
||||||
|
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
||||||
|
} else if (assetProxyId == STATIC_CALL_PROXY_ID) {
|
||||||
|
// The StaticCallProxy does not require any approvals
|
||||||
|
allowance = _MAX_UINT256;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allowance will be 0 if the assetProxyId is unknown
|
||||||
|
return allowance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls getAssetProxyAllowance() for each element of assetData.
|
||||||
|
/// @param ownerAddress Owner of the assets specified by assetData.
|
||||||
|
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
|
||||||
|
/// @return An array of asset allowances from getAllowance(), with each
|
||||||
|
/// element corresponding to the same-indexed element in the assetData input.
|
||||||
|
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory allowances)
|
||||||
|
{
|
||||||
|
uint256 length = assetData.length;
|
||||||
|
allowances = new uint256[](length);
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
|
||||||
|
}
|
||||||
|
return allowances;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls getBalance() and getAllowance() for assetData.
|
||||||
|
/// @param ownerAddress Owner of the assets specified by assetData.
|
||||||
|
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
|
||||||
|
/// @return Number of assets (or asset baskets) held by owner, and number
|
||||||
|
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
||||||
|
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256 balance, uint256 allowance)
|
||||||
|
{
|
||||||
|
balance = getBalance(ownerAddress, assetData);
|
||||||
|
allowance = getAssetProxyAllowance(ownerAddress, assetData);
|
||||||
|
return (balance, allowance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData.
|
||||||
|
/// @param ownerAddress Owner of the assets specified by assetData.
|
||||||
|
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
|
||||||
|
/// @return An array of asset balances from getBalance(), and an array of
|
||||||
|
/// asset allowances from getAllowance(), with each element
|
||||||
|
/// corresponding to the same-indexed element in the assetData input.
|
||||||
|
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory balances, uint256[] memory allowances)
|
||||||
|
{
|
||||||
|
balances = getBatchBalances(ownerAddress, assetData);
|
||||||
|
allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
|
||||||
|
return (balances, allowances);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification.
|
||||||
|
/// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded.
|
||||||
|
/// @return AssetProxy-compliant data describing the asset.
|
||||||
|
function encodeERC20AssetData(address tokenAddress)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bytes memory assetData)
|
||||||
|
{
|
||||||
|
assetData = abi.encodeWithSelector(ERC20_PROXY_ID, tokenAddress);
|
||||||
|
return assetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification.
|
||||||
|
/// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset.
|
||||||
|
/// @return The ERC-20 AssetProxy identifier, and the address of the ERC-20
|
||||||
|
/// contract hosting this asset.
|
||||||
|
function decodeERC20AssetData(bytes memory assetData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
bytes4 assetProxyId,
|
||||||
|
address tokenAddress
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
require(
|
||||||
|
assetProxyId == ERC20_PROXY_ID,
|
||||||
|
"WRONG_PROXY_ID"
|
||||||
|
);
|
||||||
|
|
||||||
|
tokenAddress = assetData.readAddress(16);
|
||||||
|
return (assetProxyId, tokenAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification.
|
||||||
|
/// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded.
|
||||||
|
/// @param tokenId The identifier of the specific asset to be traded.
|
||||||
|
/// @return AssetProxy-compliant asset data describing the asset.
|
||||||
|
function encodeERC721AssetData(address tokenAddress, uint256 tokenId)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bytes memory assetData)
|
||||||
|
{
|
||||||
|
assetData = abi.encodeWithSelector(
|
||||||
|
ERC721_PROXY_ID,
|
||||||
|
tokenAddress,
|
||||||
|
tokenId
|
||||||
|
);
|
||||||
|
return assetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification.
|
||||||
|
/// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset.
|
||||||
|
/// @return The ERC-721 AssetProxy identifier, the address of the ERC-721
|
||||||
|
/// contract hosting this asset, and the identifier of the specific
|
||||||
|
/// asset to be traded.
|
||||||
|
function decodeERC721AssetData(bytes memory assetData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
bytes4 assetProxyId,
|
||||||
|
address tokenAddress,
|
||||||
|
uint256 tokenId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
require(
|
||||||
|
assetProxyId == ERC721_PROXY_ID,
|
||||||
|
"WRONG_PROXY_ID"
|
||||||
|
);
|
||||||
|
|
||||||
|
tokenAddress = assetData.readAddress(16);
|
||||||
|
tokenId = assetData.readUint256(36);
|
||||||
|
return (assetProxyId, tokenAddress, tokenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification.
|
||||||
|
/// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded.
|
||||||
|
/// @param tokenIds The identifiers of the specific assets to be traded.
|
||||||
|
/// @param tokenValues The amounts of each asset to be traded.
|
||||||
|
/// @param callbackData Data to be passed to receiving contracts when a transfer is performed.
|
||||||
|
/// @return AssetProxy-compliant asset data describing the set of assets.
|
||||||
|
function encodeERC1155AssetData(
|
||||||
|
address tokenAddress,
|
||||||
|
uint256[] memory tokenIds,
|
||||||
|
uint256[] memory tokenValues,
|
||||||
|
bytes memory callbackData
|
||||||
|
)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bytes memory assetData)
|
||||||
|
{
|
||||||
|
assetData = abi.encodeWithSelector(
|
||||||
|
ERC1155_PROXY_ID,
|
||||||
|
tokenAddress,
|
||||||
|
tokenIds,
|
||||||
|
tokenValues,
|
||||||
|
callbackData
|
||||||
|
);
|
||||||
|
return assetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification.
|
||||||
|
/// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets.
|
||||||
|
/// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155
|
||||||
|
/// contract hosting the assets, an array of the identifiers of the
|
||||||
|
/// assets to be traded, an array of asset amounts to be traded, and
|
||||||
|
/// callback data. Each element of the arrays corresponds to the
|
||||||
|
/// same-indexed element of the other array. Return values specified as
|
||||||
|
/// `memory` are returned as pointers to locations within the memory of
|
||||||
|
/// the input parameter `assetData`.
|
||||||
|
function decodeERC1155AssetData(bytes memory assetData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
bytes4 assetProxyId,
|
||||||
|
address tokenAddress,
|
||||||
|
uint256[] memory tokenIds,
|
||||||
|
uint256[] memory tokenValues,
|
||||||
|
bytes memory callbackData
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
require(
|
||||||
|
assetProxyId == ERC1155_PROXY_ID,
|
||||||
|
"WRONG_PROXY_ID"
|
||||||
|
);
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
// Skip selector and length to get to the first parameter:
|
||||||
|
assetData := add(assetData, 36)
|
||||||
|
// Read the value of the first parameter:
|
||||||
|
tokenAddress := mload(assetData)
|
||||||
|
// Point to the next parameter's data:
|
||||||
|
tokenIds := add(assetData, mload(add(assetData, 32)))
|
||||||
|
// Point to the next parameter's data:
|
||||||
|
tokenValues := add(assetData, mload(add(assetData, 64)))
|
||||||
|
// Point to the next parameter's data:
|
||||||
|
callbackData := add(assetData, mload(add(assetData, 96)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
assetProxyId,
|
||||||
|
tokenAddress,
|
||||||
|
tokenIds,
|
||||||
|
tokenValues,
|
||||||
|
callbackData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Encode data for multiple assets, per the AssetProxy contract specification.
|
||||||
|
/// @param amounts The amounts of each asset to be traded.
|
||||||
|
/// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded.
|
||||||
|
/// @return AssetProxy-compliant data describing the set of assets.
|
||||||
|
function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bytes memory assetData)
|
||||||
|
{
|
||||||
|
assetData = abi.encodeWithSelector(
|
||||||
|
MULTI_ASSET_PROXY_ID,
|
||||||
|
amounts,
|
||||||
|
nestedAssetData
|
||||||
|
);
|
||||||
|
return assetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Decode multi-asset data from the format described in the AssetProxy contract specification.
|
||||||
|
/// @param assetData AssetProxy-compliant data describing a multi-asset basket.
|
||||||
|
/// @return The Multi-Asset AssetProxy identifier, an array of the amounts
|
||||||
|
/// of the assets to be traded, and an array of the
|
||||||
|
/// AssetProxy-compliant data describing each asset to be traded. Each
|
||||||
|
/// element of the arrays corresponds to the same-indexed element of the other array.
|
||||||
|
function decodeMultiAssetData(bytes memory assetData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
bytes4 assetProxyId,
|
||||||
|
uint256[] memory amounts,
|
||||||
|
bytes[] memory nestedAssetData
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
require(
|
||||||
|
assetProxyId == MULTI_ASSET_PROXY_ID,
|
||||||
|
"WRONG_PROXY_ID"
|
||||||
|
);
|
||||||
|
|
||||||
|
// solhint-disable indent
|
||||||
|
(amounts, nestedAssetData) = abi.decode(
|
||||||
|
assetData.slice(4, assetData.length),
|
||||||
|
(uint256[], bytes[])
|
||||||
|
);
|
||||||
|
// solhint-enable indent
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls `asset.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned asset.
|
||||||
|
/// @param tokenAddress Address of ERC721 asset.
|
||||||
|
/// @param tokenId The identifier for the specific NFT.
|
||||||
|
/// @return Owner of tokenId or null address if unowned.
|
||||||
|
function getERC721TokenOwner(address tokenAddress, uint256 tokenId)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (address ownerAddress)
|
||||||
|
{
|
||||||
|
bytes memory ownerOfCalldata = abi.encodeWithSelector(
|
||||||
|
_ERC721_OWNER_OF_SELECTOR,
|
||||||
|
tokenId
|
||||||
|
);
|
||||||
|
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
||||||
|
|
||||||
|
ownerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||||
|
return ownerAddress;
|
||||||
|
}
|
||||||
|
}
|
193
contracts/dev-utils/contracts/src/LibTransactionDecoder.sol
Normal file
193
contracts/dev-utils/contracts/src/LibTransactionDecoder.sol
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract LibTransactionDecoder is
|
||||||
|
LibExchangeSelectors
|
||||||
|
{
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
/// @dev Decodes the call data for an Exchange contract method call.
|
||||||
|
/// @param transactionData ABI-encoded calldata for an Exchange
|
||||||
|
/// contract method call.
|
||||||
|
/// @return The name of the function called, and the parameters it was
|
||||||
|
/// given. For single-order fills and cancels, the arrays will have
|
||||||
|
/// just one element.
|
||||||
|
function decodeZeroExTransactionData(bytes memory transactionData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns(
|
||||||
|
string memory functionName,
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256[] memory takerAssetFillAmounts,
|
||||||
|
bytes[] memory signatures
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bytes4 functionSelector = transactionData.readBytes4(0);
|
||||||
|
|
||||||
|
if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) {
|
||||||
|
functionName = "batchCancelOrders";
|
||||||
|
} else if (functionSelector == BATCH_FILL_ORDERS_SELECTOR) {
|
||||||
|
functionName = "batchFillOrders";
|
||||||
|
} else if (functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR) {
|
||||||
|
functionName = "batchFillOrdersNoThrow";
|
||||||
|
} else if (functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR) {
|
||||||
|
functionName = "batchFillOrKillOrders";
|
||||||
|
} else if (functionSelector == CANCEL_ORDER_SELECTOR) {
|
||||||
|
functionName = "cancelOrder";
|
||||||
|
} else if (functionSelector == FILL_ORDER_SELECTOR) {
|
||||||
|
functionName = "fillOrder";
|
||||||
|
} else if (functionSelector == FILL_ORDER_NO_THROW_SELECTOR) {
|
||||||
|
functionName = "fillOrderNoThrow";
|
||||||
|
} else if (functionSelector == FILL_OR_KILL_ORDER_SELECTOR) {
|
||||||
|
functionName = "fillOrKillOrder";
|
||||||
|
} else if (functionSelector == MARKET_BUY_ORDERS_SELECTOR) {
|
||||||
|
functionName = "marketBuyOrders";
|
||||||
|
} else if (functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR) {
|
||||||
|
functionName = "marketBuyOrdersNoThrow";
|
||||||
|
} else if (functionSelector == MARKET_SELL_ORDERS_SELECTOR) {
|
||||||
|
functionName = "marketSellOrders";
|
||||||
|
} else if (functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR) {
|
||||||
|
functionName = "marketSellOrdersNoThrow";
|
||||||
|
} else if (functionSelector == MATCH_ORDERS_SELECTOR) {
|
||||||
|
functionName = "matchOrders";
|
||||||
|
} else if (
|
||||||
|
functionSelector == CANCEL_ORDERS_UP_TO_SELECTOR ||
|
||||||
|
functionSelector == EXECUTE_TRANSACTION_SELECTOR
|
||||||
|
// TODO: add new noThrow cancel functions when https://github.com/0xProject/ZEIPs/issues/35 is merged.
|
||||||
|
) {
|
||||||
|
revert("UNIMPLEMENTED");
|
||||||
|
} else {
|
||||||
|
revert("UNKNOWN_FUNCTION_SELECTOR");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) {
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
orders = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order[]));
|
||||||
|
takerAssetFillAmounts = new uint256[](0);
|
||||||
|
signatures = new bytes[](0);
|
||||||
|
} else if (
|
||||||
|
functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
||||||
|
functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
functionSelector == BATCH_FILL_ORDERS_SELECTOR
|
||||||
|
) {
|
||||||
|
(orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForBatchFill(transactionData);
|
||||||
|
} else if (functionSelector == CANCEL_ORDER_SELECTOR) {
|
||||||
|
orders = new LibOrder.Order[](1);
|
||||||
|
orders[0] = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order));
|
||||||
|
takerAssetFillAmounts = new uint256[](0);
|
||||||
|
signatures = new bytes[](0);
|
||||||
|
} else if (
|
||||||
|
functionSelector == FILL_OR_KILL_ORDER_SELECTOR ||
|
||||||
|
functionSelector == FILL_ORDER_SELECTOR ||
|
||||||
|
functionSelector == FILL_ORDER_NO_THROW_SELECTOR
|
||||||
|
) {
|
||||||
|
(orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForSingleOrderFill(transactionData);
|
||||||
|
} else if (
|
||||||
|
functionSelector == MARKET_BUY_ORDERS_SELECTOR ||
|
||||||
|
functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
functionSelector == MARKET_SELL_ORDERS_SELECTOR ||
|
||||||
|
functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||||
|
) {
|
||||||
|
(orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForMarketFill(transactionData);
|
||||||
|
} else if (functionSelector == MATCH_ORDERS_SELECTOR) {
|
||||||
|
(
|
||||||
|
LibOrder.Order memory leftOrder,
|
||||||
|
LibOrder.Order memory rightOrder,
|
||||||
|
bytes memory leftSignature,
|
||||||
|
bytes memory rightSignature
|
||||||
|
) = abi.decode(
|
||||||
|
transactionData.slice(4, transactionData.length),
|
||||||
|
(LibOrder.Order, LibOrder.Order, bytes, bytes)
|
||||||
|
);
|
||||||
|
|
||||||
|
orders = new LibOrder.Order[](2);
|
||||||
|
orders[0] = leftOrder;
|
||||||
|
orders[1] = rightOrder;
|
||||||
|
|
||||||
|
takerAssetFillAmounts = new uint256[](2);
|
||||||
|
takerAssetFillAmounts[0] = leftOrder.takerAssetAmount;
|
||||||
|
takerAssetFillAmounts[1] = rightOrder.takerAssetAmount;
|
||||||
|
|
||||||
|
signatures = new bytes[](2);
|
||||||
|
signatures[0] = leftSignature;
|
||||||
|
signatures[1] = rightSignature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _makeReturnValuesForSingleOrderFill(bytes memory transactionData)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256[] memory takerAssetFillAmounts,
|
||||||
|
bytes[] memory signatures
|
||||||
|
)
|
||||||
|
{
|
||||||
|
orders = new LibOrder.Order[](1);
|
||||||
|
takerAssetFillAmounts = new uint256[](1);
|
||||||
|
signatures = new bytes[](1);
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
(orders[0], takerAssetFillAmounts[0], signatures[0]) = abi.decode(
|
||||||
|
transactionData.slice(4, transactionData.length),
|
||||||
|
(LibOrder.Order, uint256, bytes)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _makeReturnValuesForBatchFill(bytes memory transactionData)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256[] memory takerAssetFillAmounts,
|
||||||
|
bytes[] memory signatures
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
(orders, takerAssetFillAmounts, signatures) = abi.decode(
|
||||||
|
transactionData.slice(4, transactionData.length),
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
(LibOrder.Order[], uint256[], bytes[])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _makeReturnValuesForMarketFill(bytes memory transactionData)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256[] memory takerAssetFillAmounts,
|
||||||
|
bytes[] memory signatures
|
||||||
|
)
|
||||||
|
{
|
||||||
|
takerAssetFillAmounts = new uint256[](1);
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
(orders, takerAssetFillAmounts[0], signatures) = abi.decode(
|
||||||
|
transactionData.slice(4, transactionData.length),
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
(LibOrder.Order[], uint256, bytes[])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
184
contracts/dev-utils/contracts/src/OrderValidationUtils.sol
Normal file
184
contracts/dev-utils/contracts/src/OrderValidationUtils.sol
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
|
import "./LibAssetData.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract OrderValidationUtils is
|
||||||
|
LibAssetData,
|
||||||
|
LibMath
|
||||||
|
{
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
// solhint-disable var-name-mixedcase
|
||||||
|
bytes internal _ZRX_ASSET_DATA;
|
||||||
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
|
constructor (address _exchange, bytes memory _zrxAssetData)
|
||||||
|
public
|
||||||
|
LibAssetData(_exchange)
|
||||||
|
{
|
||||||
|
_ZRX_ASSET_DATA = _zrxAssetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||||
|
/// @param order The order structure.
|
||||||
|
/// @param signature Signature provided by maker that proves the order's authenticity.
|
||||||
|
/// `0x01` can always be provided if the signature does not need to be validated.
|
||||||
|
/// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order),
|
||||||
|
/// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state),
|
||||||
|
/// and isValidSignature (validity of the provided signature).
|
||||||
|
/// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
|
||||||
|
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
|
||||||
|
/// amount of each asset that can be filled.
|
||||||
|
function getOrderRelevantState(LibOrder.Order memory order, bytes memory signature)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
LibOrder.OrderInfo memory orderInfo,
|
||||||
|
uint256 fillableTakerAssetAmount,
|
||||||
|
bool isValidSignature
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Get info specific to order
|
||||||
|
orderInfo = _EXCHANGE.getOrderInfo(order);
|
||||||
|
|
||||||
|
// Validate the maker's signature
|
||||||
|
address makerAddress = order.makerAddress;
|
||||||
|
isValidSignature = _EXCHANGE.isValidSignature(
|
||||||
|
orderInfo.orderHash,
|
||||||
|
makerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get the transferable amount of the `makerAsset`
|
||||||
|
uint256 transferableMakerAssetAmount = getTransferableAssetAmount(makerAddress, order.makerAssetData);
|
||||||
|
|
||||||
|
// Assign to stack variables to reduce redundant mloads/sloads
|
||||||
|
uint256 takerAssetAmount = order.takerAssetAmount;
|
||||||
|
uint256 makerFee = order.makerFee;
|
||||||
|
bytes memory zrxAssetData = _ZRX_ASSET_DATA;
|
||||||
|
|
||||||
|
// Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset`, `makerFeeAsset`,
|
||||||
|
// and the total amounts specified in the order
|
||||||
|
uint256 transferableTakerAssetAmount;
|
||||||
|
if (order.makerAssetData.equals(zrxAssetData)) {
|
||||||
|
// If `makerAsset` equals `makerFeeAsset`, the % that can be filled is
|
||||||
|
// transferableMakerAssetAmount / (makerAssetAmount + makerFee)
|
||||||
|
transferableTakerAssetAmount = getPartialAmountFloor(
|
||||||
|
transferableMakerAssetAmount,
|
||||||
|
safeAdd(order.makerAssetAmount, makerFee),
|
||||||
|
takerAssetAmount
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Get the transferable amount of the `makerFeeAsset`
|
||||||
|
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, zrxAssetData);
|
||||||
|
|
||||||
|
// If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount)
|
||||||
|
if (makerFee == 0) {
|
||||||
|
transferableTakerAssetAmount = getPartialAmountFloor(
|
||||||
|
transferableMakerAssetAmount,
|
||||||
|
order.makerAssetAmount,
|
||||||
|
takerAssetAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
// If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of
|
||||||
|
// (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee)
|
||||||
|
} else {
|
||||||
|
uint256 transferableMakerToTakerAmount = getPartialAmountFloor(
|
||||||
|
transferableMakerAssetAmount,
|
||||||
|
order.makerAssetAmount,
|
||||||
|
takerAssetAmount
|
||||||
|
);
|
||||||
|
uint256 transferableMakerFeeToTakerAmount = getPartialAmountFloor(
|
||||||
|
transferableMakerFeeAssetAmount,
|
||||||
|
makerFee,
|
||||||
|
takerAssetAmount
|
||||||
|
);
|
||||||
|
transferableTakerAssetAmount = min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount`
|
||||||
|
fillableTakerAssetAmount = min256(
|
||||||
|
safeSub(takerAssetAmount, orderInfo.orderTakerAssetFilledAmount),
|
||||||
|
transferableTakerAssetAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Fetches all order-relevant information needed to validate if the supplied orders are fillable.
|
||||||
|
/// @param orders Array of order structures.
|
||||||
|
/// @param signatures Array of signatures provided by makers that prove the authenticity of the orders.
|
||||||
|
/// `0x01` can always be provided if a signature does not need to be validated.
|
||||||
|
/// @return The ordersInfo (array of the hash, status, and `takerAssetAmount` already filled for each order),
|
||||||
|
/// fillableTakerAssetAmounts (array of amounts for each order's `takerAssetAmount` that is fillable given all on-chain state),
|
||||||
|
/// and isValidSignature (array containing the validity of each provided signature).
|
||||||
|
/// NOTE: If the `takerAssetData` encodes data for multiple assets, each element of `fillableTakerAssetAmounts`
|
||||||
|
/// will represent a "scaled" amount, meaning it must be multiplied by all the individual asset amounts within
|
||||||
|
/// the `takerAssetData` to get the final amount of each asset that can be filled.
|
||||||
|
function getOrderRelevantStates(LibOrder.Order[] memory orders, bytes[] memory signatures)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
LibOrder.OrderInfo[] memory ordersInfo,
|
||||||
|
uint256[] memory fillableTakerAssetAmounts,
|
||||||
|
bool[] memory isValidSignature
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint256 length = orders.length;
|
||||||
|
ordersInfo = new LibOrder.OrderInfo[](length);
|
||||||
|
fillableTakerAssetAmounts = new uint256[](length);
|
||||||
|
isValidSignature = new bool[](length);
|
||||||
|
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
(ordersInfo[i], fillableTakerAssetAmounts[i], isValidSignature[i]) = getOrderRelevantState(
|
||||||
|
orders[i],
|
||||||
|
signatures[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ordersInfo, fillableTakerAssetAmounts, isValidSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Gets the amount of an asset transferable by the owner.
|
||||||
|
/// @param ownerAddress Address of the owner of the asset.
|
||||||
|
/// @param assetData Description of tokens, per the AssetProxy contract specification.
|
||||||
|
/// @return The amount of the asset tranferable by the owner.
|
||||||
|
/// NOTE: If the `assetData` encodes data for multiple assets, the `transferableAssetAmount`
|
||||||
|
/// will represent the amount of times the entire `assetData` can be transferred. To calculate
|
||||||
|
/// the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by
|
||||||
|
/// the individual asset amounts located within the `assetData`.
|
||||||
|
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256 transferableAssetAmount)
|
||||||
|
{
|
||||||
|
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
|
||||||
|
transferableAssetAmount = min256(balance, allowance);
|
||||||
|
return transferableAssetAmount;
|
||||||
|
}
|
||||||
|
}
|
91
contracts/dev-utils/package.json
Normal file
91
contracts/dev-utils/package.json
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"name": "@0x/contracts-dev-utils",
|
||||||
|
"version": "0.0.3",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.12"
|
||||||
|
},
|
||||||
|
"description": "0x protocol specific utility contracts",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn pre_build && tsc -b",
|
||||||
|
"build:ci": "yarn build",
|
||||||
|
"pre_build": "run-s compile generate_contract_wrappers",
|
||||||
|
"test": "yarn run_mocha",
|
||||||
|
"rebuild_and_test": "run-s build test",
|
||||||
|
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||||
|
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||||
|
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||||
|
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||||
|
"compile": "sol-compiler",
|
||||||
|
"watch": "sol-compiler -w",
|
||||||
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"coverage:report:text": "istanbul report text",
|
||||||
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"coverage:report:lcov": "istanbul report lcov",
|
||||||
|
"test:circleci": "yarn test",
|
||||||
|
"contracts:gen": "contracts-gen",
|
||||||
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"abis": "./generated-artifacts/@(DevUtils|LibAssetData|LibTransactionDecoder|EthBalanceChecker).json",
|
||||||
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@0x/abi-gen": "^2.1.1",
|
||||||
|
"@0x/contract-wrappers": "^9.1.6",
|
||||||
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
|
"@0x/dev-utils": "^2.2.4",
|
||||||
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
|
"@0x/tslint-config": "^3.0.1",
|
||||||
|
"@types/lodash": "4.14.104",
|
||||||
|
"@types/node": "*",
|
||||||
|
"chai": "^4.0.1",
|
||||||
|
"chai-as-promised": "^7.1.0",
|
||||||
|
"chai-bignumber": "^3.0.0",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"make-promises-safe": "^1.1.0",
|
||||||
|
"mocha": "^4.1.0",
|
||||||
|
"npm-run-all": "^4.1.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"solhint": "^1.4.1",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"typescript": "3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@0x/base-contract": "^5.1.1",
|
||||||
|
"@0x/contracts-asset-proxy": "^2.2.1",
|
||||||
|
"@0x/contracts-erc1155": "^1.1.8",
|
||||||
|
"@0x/contracts-erc20": "^2.2.7",
|
||||||
|
"@0x/contracts-erc721": "^2.1.8",
|
||||||
|
"@0x/contracts-exchange": "^2.1.7",
|
||||||
|
"@0x/contracts-exchange-libs": "^3.0.1",
|
||||||
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
|
"@0x/order-utils": "^8.2.1",
|
||||||
|
"@0x/types": "^2.4.0",
|
||||||
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
|
"@0x/utils": "^4.4.0",
|
||||||
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
|
"ethereum-types": "^2.1.3",
|
||||||
|
"ethereumjs-util": "^5.1.1"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
15
contracts/dev-utils/src/artifacts.ts
Normal file
15
contracts/dev-utils/src/artifacts.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as DevUtils from '../generated-artifacts/DevUtils.json';
|
||||||
|
import * as LibAssetData from '../generated-artifacts/LibAssetData.json';
|
||||||
|
import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json';
|
||||||
|
export const artifacts = {
|
||||||
|
DevUtils: DevUtils as ContractArtifact,
|
||||||
|
LibTransactionDecoder: LibTransactionDecoder as ContractArtifact,
|
||||||
|
LibAssetData: LibAssetData as ContractArtifact,
|
||||||
|
};
|
2
contracts/dev-utils/src/index.ts
Normal file
2
contracts/dev-utils/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './artifacts';
|
||||||
|
export * from './wrappers';
|
8
contracts/dev-utils/src/wrappers.ts
Normal file
8
contracts/dev-utils/src/wrappers.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
export * from '../generated-wrappers/dev_utils';
|
||||||
|
export * from '../generated-wrappers/lib_asset_data';
|
||||||
|
export * from '../generated-wrappers/lib_transaction_decoder';
|
19
contracts/dev-utils/test/global_hooks.ts
Normal file
19
contracts/dev-utils/test/global_hooks.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { env, EnvVars } from '@0x/dev-utils';
|
||||||
|
|
||||||
|
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
|
||||||
|
import { providerUtils } from '@0x/utils';
|
||||||
|
|
||||||
|
before('start web3 provider', () => {
|
||||||
|
providerUtils.startProviderEngine(provider);
|
||||||
|
});
|
||||||
|
after('generate coverage report', async () => {
|
||||||
|
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
|
||||||
|
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||||
|
await coverageSubprovider.writeCoverageAsync();
|
||||||
|
}
|
||||||
|
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
|
||||||
|
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||||
|
await profilerSubprovider.writeProfilerOutputAsync();
|
||||||
|
}
|
||||||
|
provider.stop();
|
||||||
|
});
|
527
contracts/dev-utils/test/lib_asset_data.ts
Normal file
527
contracts/dev-utils/test/lib_asset_data.ts
Normal file
@@ -0,0 +1,527 @@
|
|||||||
|
import * as chai from 'chai';
|
||||||
|
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||||
|
|
||||||
|
import {
|
||||||
|
artifacts as proxyArtifacts,
|
||||||
|
ERC1155ProxyContract,
|
||||||
|
ERC20ProxyContract,
|
||||||
|
ERC721ProxyContract,
|
||||||
|
MultiAssetProxyContract,
|
||||||
|
StaticCallProxyContract,
|
||||||
|
TestStaticCallTargetContract,
|
||||||
|
} from '@0x/contracts-asset-proxy';
|
||||||
|
import {
|
||||||
|
artifacts as erc1155Artifacts,
|
||||||
|
ERC1155MintableContract,
|
||||||
|
ERC1155TransferSingleEventArgs,
|
||||||
|
} from '@0x/contracts-erc1155';
|
||||||
|
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
|
import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||||
|
import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
|
||||||
|
import { chaiSetup, constants, LogDecoder, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { AssetProxyId } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
|
import { artifacts, LibAssetDataContract } from '../src';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
|
||||||
|
const KNOWN_ERC20_ENCODING = {
|
||||||
|
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
|
assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
|
};
|
||||||
|
const KNOWN_ERC721_ENCODING = {
|
||||||
|
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
|
tokenId: new BigNumber(1),
|
||||||
|
assetData:
|
||||||
|
'0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
|
||||||
|
};
|
||||||
|
const KNOWN_ERC1155_ENCODING = {
|
||||||
|
tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
|
tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)],
|
||||||
|
tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)],
|
||||||
|
callbackData:
|
||||||
|
'0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
|
||||||
|
assetData:
|
||||||
|
'0xa7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
|
||||||
|
};
|
||||||
|
const KNOWN_MULTI_ASSET_ENCODING = {
|
||||||
|
amounts: [new BigNumber(70), new BigNumber(1), new BigNumber(18)],
|
||||||
|
nestedAssetData: [
|
||||||
|
KNOWN_ERC20_ENCODING.assetData,
|
||||||
|
KNOWN_ERC721_ENCODING.assetData,
|
||||||
|
KNOWN_ERC1155_ENCODING.assetData,
|
||||||
|
],
|
||||||
|
assetData:
|
||||||
|
'0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('LibAssetData', () => {
|
||||||
|
let exchange: ExchangeContract;
|
||||||
|
let erc20Proxy: ERC20ProxyContract;
|
||||||
|
let erc721Proxy: ERC721ProxyContract;
|
||||||
|
let erc1155Proxy: ERC1155ProxyContract;
|
||||||
|
let multiAssetProxy: MultiAssetProxyContract;
|
||||||
|
let staticCallProxy: StaticCallProxyContract;
|
||||||
|
let staticCallTarget: TestStaticCallTargetContract;
|
||||||
|
let libAssetData: LibAssetDataContract;
|
||||||
|
|
||||||
|
let tokenOwnerAddress: string;
|
||||||
|
|
||||||
|
let erc20Token: DummyERC20TokenContract;
|
||||||
|
let erc721Token: DummyERC721TokenContract;
|
||||||
|
let erc1155Token: ERC1155MintableContract;
|
||||||
|
|
||||||
|
const erc20TokenTotalSupply = new BigNumber(1);
|
||||||
|
|
||||||
|
const firstERC721TokenId = new BigNumber(1);
|
||||||
|
const numberOfERC721Tokens = 10;
|
||||||
|
|
||||||
|
let erc1155TokenId: BigNumber;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
|
||||||
|
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
|
exchangeArtifacts.Exchange,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
);
|
||||||
|
|
||||||
|
erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.ERC20Proxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.ERC721Proxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.ERC1155Proxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.MultiAssetProxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.StaticCallProxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
|
||||||
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc20Proxy.address);
|
||||||
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc721Proxy.address);
|
||||||
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc1155Proxy.address);
|
||||||
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(multiAssetProxy.address);
|
||||||
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(staticCallProxy.address);
|
||||||
|
|
||||||
|
libAssetData = await LibAssetDataContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.LibAssetData,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
exchange.address,
|
||||||
|
);
|
||||||
|
|
||||||
|
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.TestStaticCallTarget,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
|
||||||
|
[tokenOwnerAddress] = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
|
||||||
|
erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||||
|
erc20Artifacts.DummyERC20Token,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
'Dummy',
|
||||||
|
'DUM',
|
||||||
|
new BigNumber(1),
|
||||||
|
erc20TokenTotalSupply,
|
||||||
|
);
|
||||||
|
|
||||||
|
erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
|
||||||
|
erc721Artifacts.DummyERC721Token,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
'Dummy',
|
||||||
|
'DUM',
|
||||||
|
);
|
||||||
|
// mint `numberOfERC721Tokens` tokens
|
||||||
|
const transactionMinedPromises = [];
|
||||||
|
for (let i = 0; i < numberOfERC721Tokens; i++) {
|
||||||
|
transactionMinedPromises.push(
|
||||||
|
erc721Token.mint.awaitTransactionSuccessAsync(tokenOwnerAddress, firstERC721TokenId.plus(i - 1)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await Promise.all(transactionMinedPromises);
|
||||||
|
|
||||||
|
erc1155Token = await ERC1155MintableContract.deployFrom0xArtifactAsync(
|
||||||
|
erc1155Artifacts.ERC1155Mintable,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
|
||||||
|
const logDecoder = new LogDecoder(web3Wrapper, erc1155Artifacts);
|
||||||
|
const transactionReceipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||||
|
await erc1155Token.create.sendTransactionAsync('uri:Dummy', /*isNonFungible:*/ false),
|
||||||
|
);
|
||||||
|
|
||||||
|
// tslint:disable-next-line no-unnecessary-type-assertion
|
||||||
|
erc1155TokenId = (transactionReceipt.logs[0] as LogWithDecodedArgs<ERC1155TransferSingleEventArgs>).args.id;
|
||||||
|
await erc1155Token.mintFungible.awaitTransactionSuccessAsync(
|
||||||
|
erc1155TokenId,
|
||||||
|
[tokenOwnerAddress],
|
||||||
|
[new BigNumber(1)],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a deployed-to address', () => {
|
||||||
|
expect(libAssetData.address.slice(0, 2)).to.equal('0x');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('encoding and decoding', () => {
|
||||||
|
it('should encode ERC20 asset data', async () => {
|
||||||
|
expect(await libAssetData.encodeERC20AssetData.callAsync(KNOWN_ERC20_ENCODING.address)).to.equal(
|
||||||
|
KNOWN_ERC20_ENCODING.assetData,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decode ERC20 asset data', async () => {
|
||||||
|
expect(await libAssetData.decodeERC20AssetData.callAsync(KNOWN_ERC20_ENCODING.assetData)).to.deep.equal([
|
||||||
|
AssetProxyId.ERC20,
|
||||||
|
KNOWN_ERC20_ENCODING.address,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encode ERC721 asset data', async () => {
|
||||||
|
expect(
|
||||||
|
await libAssetData.encodeERC721AssetData.callAsync(
|
||||||
|
KNOWN_ERC721_ENCODING.address,
|
||||||
|
KNOWN_ERC721_ENCODING.tokenId,
|
||||||
|
),
|
||||||
|
).to.equal(KNOWN_ERC721_ENCODING.assetData);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decode ERC721 asset data', async () => {
|
||||||
|
expect(await libAssetData.decodeERC721AssetData.callAsync(KNOWN_ERC721_ENCODING.assetData)).to.deep.equal([
|
||||||
|
AssetProxyId.ERC721,
|
||||||
|
KNOWN_ERC721_ENCODING.address,
|
||||||
|
KNOWN_ERC721_ENCODING.tokenId,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encode ERC1155 asset data', async () => {
|
||||||
|
expect(
|
||||||
|
await libAssetData.encodeERC1155AssetData.callAsync(
|
||||||
|
KNOWN_ERC1155_ENCODING.tokenAddress,
|
||||||
|
KNOWN_ERC1155_ENCODING.tokenIds,
|
||||||
|
KNOWN_ERC1155_ENCODING.tokenValues,
|
||||||
|
KNOWN_ERC1155_ENCODING.callbackData,
|
||||||
|
),
|
||||||
|
).to.equal(KNOWN_ERC1155_ENCODING.assetData);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decode ERC1155 asset data', async () => {
|
||||||
|
expect(await libAssetData.decodeERC1155AssetData.callAsync(KNOWN_ERC1155_ENCODING.assetData)).to.deep.equal(
|
||||||
|
[
|
||||||
|
AssetProxyId.ERC1155,
|
||||||
|
KNOWN_ERC1155_ENCODING.tokenAddress,
|
||||||
|
KNOWN_ERC1155_ENCODING.tokenIds,
|
||||||
|
KNOWN_ERC1155_ENCODING.tokenValues,
|
||||||
|
KNOWN_ERC1155_ENCODING.callbackData,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encode multiasset data', async () => {
|
||||||
|
expect(
|
||||||
|
await libAssetData.encodeMultiAssetData.callAsync(
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.amounts,
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
|
||||||
|
),
|
||||||
|
).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decode multiasset data', async () => {
|
||||||
|
expect(
|
||||||
|
await libAssetData.decodeMultiAssetData.callAsync(KNOWN_MULTI_ASSET_ENCODING.assetData),
|
||||||
|
).to.deep.equal([
|
||||||
|
AssetProxyId.MultiAsset,
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.amounts,
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getBalance', () => {
|
||||||
|
it('should query ERC20 balance by asset data', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
expect(await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData)).to.bignumber.equal(
|
||||||
|
erc20TokenTotalSupply,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if ERC20 token does not exist', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeERC20AssetData(constants.NULL_ADDRESS);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query ERC721 balance by asset data', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId);
|
||||||
|
expect(await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData)).to.bignumber.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if ERC721 token does not exist', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(constants.NULL_ADDRESS, firstERC721TokenId);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query ERC1155 balances by asset data', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
|
erc1155Token.address,
|
||||||
|
[erc1155TokenId],
|
||||||
|
[new BigNumber(1)],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
);
|
||||||
|
expect(await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData)).to.bignumber.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if ERC1155 token does not exist', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
|
constants.NULL_ADDRESS,
|
||||||
|
[erc1155TokenId],
|
||||||
|
[new BigNumber(1)],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query multi-asset batch balance by asset data', async () => {
|
||||||
|
const assetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
[new BigNumber(1), new BigNumber(1)],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(erc20Token.address),
|
||||||
|
assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
expect(await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData)).to.bignumber.equal(
|
||||||
|
Math.min(erc20TokenTotalSupply.toNumber(), numberOfERC721Tokens),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a balance of 0 if the assetData does not correspond to an AssetProxy contract', async () => {
|
||||||
|
const fakeAssetData = '0x01020304';
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, fakeAssetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a balance of MAX_UINT256 if the the StaticCallProxy assetData contains data for a successful staticcall', async () => {
|
||||||
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||||
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a balance of 0 if the the StaticCallProxy assetData contains data for an unsuccessful staticcall', async () => {
|
||||||
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
|
||||||
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getAssetProxyAllowance', () => {
|
||||||
|
it('should query ERC20 allowances by asset data', async () => {
|
||||||
|
const allowance = new BigNumber(1);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData),
|
||||||
|
).to.bignumber.equal(allowance);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query ERC721 approval by asset data', async () => {
|
||||||
|
await erc721Token.approve.awaitTransactionSuccessAsync(erc721Proxy.address, firstERC721TokenId, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData),
|
||||||
|
).to.bignumber.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query ERC721 approvalForAll by assetData', async () => {
|
||||||
|
await erc721Token.setApprovalForAll.awaitTransactionSuccessAsync(erc721Proxy.address, true, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData),
|
||||||
|
).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query ERC1155 allowances by asset data', async () => {
|
||||||
|
await erc1155Token.setApprovalForAll.awaitTransactionSuccessAsync(erc1155Proxy.address, true, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
|
erc1155Token.address,
|
||||||
|
[erc1155TokenId],
|
||||||
|
[new BigNumber(1)],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData),
|
||||||
|
).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should query multi-asset allowances by asset data', async () => {
|
||||||
|
const allowance = new BigNumber(1);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
await erc721Token.approve.awaitTransactionSuccessAsync(erc721Proxy.address, firstERC721TokenId, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
[new BigNumber(1), new BigNumber(1)],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(erc20Token.address),
|
||||||
|
assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData),
|
||||||
|
).to.bignumber.equal(1);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an allowance of 0 if the assetData does not correspond to an AssetProxy contract', async () => {
|
||||||
|
const fakeAssetData = '0x01020304';
|
||||||
|
const allowance = await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, fakeAssetData);
|
||||||
|
expect(allowance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an allowance of MAX_UINT256 for any staticCallAssetData', async () => {
|
||||||
|
const staticCallData = AssetProxyId.StaticCall;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
constants.KECCAK256_NULL,
|
||||||
|
);
|
||||||
|
const allowance = await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(allowance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getBatchBalances', () => {
|
||||||
|
it('should query balances for a batch of asset data strings', async () => {
|
||||||
|
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getBatchBalances.callAsync(tokenOwnerAddress, [erc20AssetData, erc721AssetData]),
|
||||||
|
).to.deep.equal([new BigNumber(erc20TokenTotalSupply), new BigNumber(1)]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getERC721TokenOwner', async () => {
|
||||||
|
it('should return the null address when tokenId is not owned', async () => {
|
||||||
|
const nonexistentTokenId = new BigNumber(1234567890);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getERC721TokenOwner.callAsync(erc721Token.address, nonexistentTokenId),
|
||||||
|
).to.be.equal(constants.NULL_ADDRESS);
|
||||||
|
});
|
||||||
|
it('should return the owner address when tokenId is owned', async () => {
|
||||||
|
expect(
|
||||||
|
await libAssetData.getERC721TokenOwner.callAsync(erc721Token.address, firstERC721TokenId),
|
||||||
|
).to.be.equal(tokenOwnerAddress);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getBalanceAndAllowance', () => {
|
||||||
|
it('should query balance and allowance together, from asset data', async () => {
|
||||||
|
const allowance = new BigNumber(1);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getBalanceAndAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData),
|
||||||
|
).to.deep.equal([new BigNumber(erc20TokenTotalSupply), allowance]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('getBatchBalancesAndAllowances', () => {
|
||||||
|
it('should query balances and allowances together, from an asset data array', async () => {
|
||||||
|
const allowance = new BigNumber(1);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const assetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getBatchBalancesAndAssetProxyAllowances.callAsync(tokenOwnerAddress, [assetData]),
|
||||||
|
).to.deep.equal([[new BigNumber(erc20TokenTotalSupply)], [allowance]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getBatchAssetProxyAllowances', () => {
|
||||||
|
it('should query allowances for a batch of asset data strings', async () => {
|
||||||
|
const allowance = new BigNumber(1);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
await erc721Token.approve.awaitTransactionSuccessAsync(erc721Proxy.address, firstERC721TokenId, {
|
||||||
|
from: tokenOwnerAddress,
|
||||||
|
});
|
||||||
|
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, firstERC721TokenId);
|
||||||
|
expect(
|
||||||
|
await libAssetData.getBatchAssetProxyAllowances.callAsync(tokenOwnerAddress, [
|
||||||
|
erc20AssetData,
|
||||||
|
erc721AssetData,
|
||||||
|
]),
|
||||||
|
).to.deep.equal([new BigNumber(1), new BigNumber(1)]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// tslint:disable:max-file-line-count
|
139
contracts/dev-utils/test/lib_transaction_decoder.ts
Normal file
139
contracts/dev-utils/test/lib_transaction_decoder.ts
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import { IExchangeContract } from '@0x/contracts-exchange';
|
||||||
|
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
|
||||||
|
import { artifacts, LibTransactionDecoderContract } from '../src';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
|
||||||
|
const order = {
|
||||||
|
makerAddress: '0xe36ea790bc9d7ab70c55260c66d52b1eca985f84',
|
||||||
|
takerAddress: '0x0000000000000000000000000000000000000000',
|
||||||
|
feeRecipientAddress: '0x78dc5d2d739606d31509c31d654056a45185ecb6',
|
||||||
|
senderAddress: '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb',
|
||||||
|
makerAssetAmount: new BigNumber('100000000000000000000'),
|
||||||
|
takerAssetAmount: new BigNumber('200000000000000000000'),
|
||||||
|
makerFee: new BigNumber('1000000000000000000'),
|
||||||
|
takerFee: new BigNumber('1000000000000000000'),
|
||||||
|
expirationTimeSeconds: new BigNumber('1552396423'),
|
||||||
|
salt: new BigNumber('66097384406870180066678463045003379626790660770396923976862707230261946348951'),
|
||||||
|
makerAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064',
|
||||||
|
takerAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3',
|
||||||
|
};
|
||||||
|
const takerAssetFillAmount = new BigNumber('100000000000000000000');
|
||||||
|
const signature =
|
||||||
|
'0x1ce8e3c600d933423172b5021158a6be2e818613ff8e762d70ef490c752fd98a626a215f09f169668990414de75a53da221c294a3002f796d004827258b641876e03';
|
||||||
|
|
||||||
|
describe('LibTransactionDecoder', () => {
|
||||||
|
let libTxDecoder: LibTransactionDecoderContract;
|
||||||
|
const exchangeInterface = new IExchangeContract(constants.NULL_ADDRESS, provider, txDefaults);
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
libTxDecoder = await LibTransactionDecoderContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.LibTransactionDecoder,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decode an Exchange.batchCancelOrders() transaction', async () => {
|
||||||
|
const input = exchangeInterface.batchCancelOrders.getABIEncodedTransactionData([order, order]);
|
||||||
|
expect(await libTxDecoder.decodeZeroExTransactionData.callAsync(input)).to.deep.equal([
|
||||||
|
'batchCancelOrders',
|
||||||
|
[order, order],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const func of ['batchFillOrders', 'batchFillOrdersNoThrow', 'batchFillOrKillOrders']) {
|
||||||
|
const input = (exchangeInterface as any)[func].getABIEncodedTransactionData(
|
||||||
|
[order, order],
|
||||||
|
[takerAssetFillAmount, takerAssetFillAmount],
|
||||||
|
[signature, signature],
|
||||||
|
);
|
||||||
|
it(`should decode an Exchange.${func}() transaction`, async () => {
|
||||||
|
expect(await libTxDecoder.decodeZeroExTransactionData.callAsync(input)).to.deep.equal([
|
||||||
|
func,
|
||||||
|
[order, order],
|
||||||
|
[takerAssetFillAmount, takerAssetFillAmount],
|
||||||
|
[signature, signature],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should decode an Exchange.cancelOrder() transaction', async () => {
|
||||||
|
const input = exchangeInterface.cancelOrder.getABIEncodedTransactionData(order);
|
||||||
|
expect(await libTxDecoder.decodeZeroExTransactionData.callAsync(input)).to.deep.equal([
|
||||||
|
'cancelOrder',
|
||||||
|
[order],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const func of ['fillOrder', 'fillOrderNoThrow', 'fillOrKillOrder']) {
|
||||||
|
const input = (exchangeInterface as any)[func].getABIEncodedTransactionData(
|
||||||
|
order,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
signature,
|
||||||
|
);
|
||||||
|
it(`should decode an Exchange.${func}() transaction`, async () => {
|
||||||
|
expect(await libTxDecoder.decodeZeroExTransactionData.callAsync(input)).to.deep.equal([
|
||||||
|
func,
|
||||||
|
[order],
|
||||||
|
[takerAssetFillAmount],
|
||||||
|
[signature],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const func of ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow']) {
|
||||||
|
const input = (exchangeInterface as any)[func].getABIEncodedTransactionData(
|
||||||
|
[order, order],
|
||||||
|
takerAssetFillAmount,
|
||||||
|
[signature, signature],
|
||||||
|
);
|
||||||
|
it(`should decode an Exchange.${func}() transaction`, async () => {
|
||||||
|
expect(await libTxDecoder.decodeZeroExTransactionData.callAsync(input)).to.deep.equal([
|
||||||
|
func,
|
||||||
|
[order, order],
|
||||||
|
[takerAssetFillAmount],
|
||||||
|
[signature, signature],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should decode an Exchange.matchOrders() transaction', async () => {
|
||||||
|
const complementaryOrder = {
|
||||||
|
...order,
|
||||||
|
makerAddress: order.takerAddress,
|
||||||
|
takerAddress: order.makerAddress,
|
||||||
|
makerAssetData: order.takerAssetData,
|
||||||
|
takerAssetData: order.makerAssetData,
|
||||||
|
makerAssetAmount: order.takerAssetAmount,
|
||||||
|
takerAssetAmount: order.makerAssetAmount,
|
||||||
|
makerFee: order.takerFee,
|
||||||
|
takerFee: order.makerFee,
|
||||||
|
};
|
||||||
|
const input = exchangeInterface.matchOrders.getABIEncodedTransactionData(
|
||||||
|
order,
|
||||||
|
complementaryOrder,
|
||||||
|
signature,
|
||||||
|
signature,
|
||||||
|
);
|
||||||
|
expect(await libTxDecoder.decodeZeroExTransactionData.callAsync(input)).to.deep.equal([
|
||||||
|
'matchOrders',
|
||||||
|
[order, complementaryOrder],
|
||||||
|
[order.takerAssetAmount, complementaryOrder.takerAssetAmount],
|
||||||
|
[signature, signature],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
442
contracts/dev-utils/test/order_validation_utils.ts
Normal file
442
contracts/dev-utils/test/order_validation_utils.ts
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
import {
|
||||||
|
artifacts as proxyArtifacts,
|
||||||
|
ERC20ProxyContract,
|
||||||
|
ERC20Wrapper,
|
||||||
|
ERC721ProxyContract,
|
||||||
|
ERC721Wrapper,
|
||||||
|
MultiAssetProxyContract,
|
||||||
|
} from '@0x/contracts-asset-proxy';
|
||||||
|
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
|
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||||
|
import { artifacts as exchangeArtifacts, ExchangeContract, ExchangeWrapper } from '@0x/contracts-exchange';
|
||||||
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
OrderFactory,
|
||||||
|
OrderStatus,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||||
|
import { SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
|
||||||
|
import { artifacts, DevUtilsContract } from '../src';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
|
||||||
|
describe('OrderValidationUtils', () => {
|
||||||
|
let makerAddress: string;
|
||||||
|
let takerAddress: string;
|
||||||
|
let owner: string;
|
||||||
|
let erc20AssetData: string;
|
||||||
|
let erc20AssetData2: string;
|
||||||
|
let erc721AssetData: string;
|
||||||
|
let zrxAssetData: string;
|
||||||
|
|
||||||
|
let erc20Token: DummyERC20TokenContract;
|
||||||
|
let erc20Token2: DummyERC20TokenContract;
|
||||||
|
let zrxToken: DummyERC20TokenContract;
|
||||||
|
let erc721Token: DummyERC721TokenContract;
|
||||||
|
let exchange: ExchangeContract;
|
||||||
|
let devUtils: DevUtilsContract;
|
||||||
|
let erc20Proxy: ERC20ProxyContract;
|
||||||
|
let erc721Proxy: ERC721ProxyContract;
|
||||||
|
let multiAssetProxy: MultiAssetProxyContract;
|
||||||
|
|
||||||
|
let signedOrder: SignedOrder;
|
||||||
|
let orderFactory: OrderFactory;
|
||||||
|
|
||||||
|
const tokenId = new BigNumber(123456789);
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
const usedAddresses = ([owner, makerAddress, takerAddress] = accounts.slice(0, 3));
|
||||||
|
|
||||||
|
const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||||
|
const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
|
||||||
|
|
||||||
|
const numDummyErc20ToDeploy = 3;
|
||||||
|
[erc20Token, zrxToken, erc20Token2] = await erc20Wrapper.deployDummyTokensAsync(
|
||||||
|
numDummyErc20ToDeploy,
|
||||||
|
constants.DUMMY_TOKEN_DECIMALS,
|
||||||
|
);
|
||||||
|
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||||
|
|
||||||
|
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
||||||
|
erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
||||||
|
|
||||||
|
zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
|
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
|
exchangeArtifacts.Exchange,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
zrxAssetData,
|
||||||
|
);
|
||||||
|
|
||||||
|
multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.MultiAssetProxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
const exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
|
||||||
|
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, { from: owner });
|
||||||
|
await erc721Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, { from: owner });
|
||||||
|
|
||||||
|
devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.DevUtils,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
exchange.address,
|
||||||
|
zrxAssetData,
|
||||||
|
);
|
||||||
|
|
||||||
|
erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20Token2.address);
|
||||||
|
erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
|
||||||
|
const defaultOrderParams = {
|
||||||
|
...constants.STATIC_ORDER_PARAMS,
|
||||||
|
exchangeAddress: exchange.address,
|
||||||
|
makerAddress,
|
||||||
|
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||||
|
makerAssetData: erc20AssetData,
|
||||||
|
takerAssetData: erc20AssetData2,
|
||||||
|
};
|
||||||
|
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||||
|
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getTransferableAssetAmount', () => {
|
||||||
|
it('should return the balance when balance < allowance', async () => {
|
||||||
|
const balance = new BigNumber(123);
|
||||||
|
const allowance = new BigNumber(456);
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, balance);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const transferableAmount = await devUtils.getTransferableAssetAmount.callAsync(
|
||||||
|
makerAddress,
|
||||||
|
erc20AssetData,
|
||||||
|
);
|
||||||
|
expect(transferableAmount).to.bignumber.equal(balance);
|
||||||
|
});
|
||||||
|
it('should return the allowance when allowance < balance', async () => {
|
||||||
|
const balance = new BigNumber(456);
|
||||||
|
const allowance = new BigNumber(123);
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, balance);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const transferableAmount = await devUtils.getTransferableAssetAmount.callAsync(
|
||||||
|
makerAddress,
|
||||||
|
erc20AssetData,
|
||||||
|
);
|
||||||
|
expect(transferableAmount).to.bignumber.equal(allowance);
|
||||||
|
});
|
||||||
|
it('should return the correct transferable amount for multiAssetData', async () => {
|
||||||
|
const multiAssetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
[new BigNumber(1), new BigNumber(1)],
|
||||||
|
[erc20AssetData, erc20AssetData2],
|
||||||
|
);
|
||||||
|
const transferableAmount1 = new BigNumber(10);
|
||||||
|
const transferableAmount2 = new BigNumber(5);
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableAmount1);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableAmount1, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await erc20Token2.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableAmount2);
|
||||||
|
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableAmount2, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const transferableAmount = await devUtils.getTransferableAssetAmount.callAsync(
|
||||||
|
makerAddress,
|
||||||
|
multiAssetData,
|
||||||
|
);
|
||||||
|
expect(transferableAmount).to.bignumber.equal(transferableAmount2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('getOrderRelevantState', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
});
|
||||||
|
it('should return the correct orderInfo when the order is valid', async () => {
|
||||||
|
const [orderInfo] = await devUtils.getOrderRelevantState.callAsync(signedOrder, signedOrder.signature);
|
||||||
|
expect(orderInfo.orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder));
|
||||||
|
expect(orderInfo.orderStatus).to.equal(OrderStatus.Fillable);
|
||||||
|
expect(orderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
it('should return isValidSignature=true when the signature is valid', async () => {
|
||||||
|
const [, , isValidSignature] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(isValidSignature).to.equal(true);
|
||||||
|
});
|
||||||
|
it('should return isValidSignature=false when the signature is invalid', async () => {
|
||||||
|
const invalidSignature = '0x01';
|
||||||
|
const [, , isValidSignature] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
invalidSignature,
|
||||||
|
);
|
||||||
|
expect(isValidSignature).to.equal(false);
|
||||||
|
});
|
||||||
|
it('should return a fillableTakerAssetAmount of 0 when balances or allowances are insufficient', async () => {
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
it('should return a fillableTakerAssetAmount of 0 when fee balances/allowances are insufficient', async () => {
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
it('should return a fillableTakerAssetAmount of 0 when balances/allowances of one asset within a multiAssetData are insufficient', async () => {
|
||||||
|
const multiAssetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
[new BigNumber(1), new BigNumber(1)],
|
||||||
|
[erc20AssetData, erc20AssetData2],
|
||||||
|
);
|
||||||
|
signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: multiAssetData });
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
it('should return the correct fillableTakerAssetAmount when fee balances/allowances are partially sufficient', async () => {
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const divisor = 4;
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(
|
||||||
|
makerAddress,
|
||||||
|
signedOrder.makerFee.dividedToIntegerBy(divisor),
|
||||||
|
);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(
|
||||||
|
signedOrder.takerAssetAmount.dividedToIntegerBy(divisor),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should return the correct fillableTakerAssetAmount when non-fee balances/allowances are partially sufficient', async () => {
|
||||||
|
const divisor = 4;
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(
|
||||||
|
makerAddress,
|
||||||
|
signedOrder.makerAssetAmount.dividedToIntegerBy(divisor),
|
||||||
|
);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(
|
||||||
|
signedOrder.takerAssetAmount.dividedToIntegerBy(divisor),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should return the correct fillableTakerAssetAmount when balances/allowances of one asset within a multiAssetData are partially sufficient', async () => {
|
||||||
|
const multiAssetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
[new BigNumber(1), new BigNumber(1)],
|
||||||
|
[erc20AssetData, erc20AssetData2],
|
||||||
|
);
|
||||||
|
signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: multiAssetData });
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const divisor = 4;
|
||||||
|
await erc20Token2.setBalance.awaitTransactionSuccessAsync(
|
||||||
|
makerAddress,
|
||||||
|
signedOrder.makerAssetAmount.dividedToIntegerBy(divisor),
|
||||||
|
);
|
||||||
|
await erc20Token2.approve.awaitTransactionSuccessAsync(
|
||||||
|
erc20Proxy.address,
|
||||||
|
signedOrder.makerAssetAmount.dividedToIntegerBy(divisor),
|
||||||
|
{
|
||||||
|
from: makerAddress,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(
|
||||||
|
signedOrder.takerAssetAmount.dividedToIntegerBy(divisor),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should return a fillableTakerAssetAmount of 0 when non-fee balances/allowances are insufficient', async () => {
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
it('should return a fillableTakerAssetAmount equal to the takerAssetAmount when the order is unfilled and balances/allowances are sufficient', async () => {
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount);
|
||||||
|
});
|
||||||
|
it('should return the correct fillableTakerAssetAmount when balances/allowances are partially sufficient and makerAsset=makerFeeAsset', async () => {
|
||||||
|
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: zrxAssetData,
|
||||||
|
makerAssetAmount: new BigNumber(10),
|
||||||
|
takerAssetAmount: new BigNumber(20),
|
||||||
|
makerFee: new BigNumber(40),
|
||||||
|
});
|
||||||
|
const transferableMakerAssetAmount = new BigNumber(10);
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableMakerAssetAmount);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableMakerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const expectedFillableTakerAssetAmount = transferableMakerAssetAmount
|
||||||
|
.times(signedOrder.takerAssetAmount)
|
||||||
|
.dividedToIntegerBy(signedOrder.makerAssetAmount.plus(signedOrder.makerFee));
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(expectedFillableTakerAssetAmount);
|
||||||
|
});
|
||||||
|
it('should return the correct fillabeTakerassetAmount when makerAsset balances/allowances are sufficient and there are no maker fees', async () => {
|
||||||
|
signedOrder = await orderFactory.newSignedOrderAsync({ makerFee: constants.ZERO_AMOUNT });
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount);
|
||||||
|
});
|
||||||
|
it('should return a fillableTakerAssetAmount when the remaining takerAssetAmount is less than the transferable amount', async () => {
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount);
|
||||||
|
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||||
|
from: takerAddress,
|
||||||
|
});
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee);
|
||||||
|
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||||
|
from: takerAddress,
|
||||||
|
});
|
||||||
|
const takerAssetFillAmount = signedOrder.takerAssetAmount.dividedToIntegerBy(4);
|
||||||
|
await exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||||
|
signedOrder,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
signedOrder.signature,
|
||||||
|
{ from: takerAddress },
|
||||||
|
);
|
||||||
|
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||||
|
signedOrder,
|
||||||
|
signedOrder.signature,
|
||||||
|
);
|
||||||
|
expect(fillableTakerAssetAmount).to.bignumber.equal(
|
||||||
|
signedOrder.takerAssetAmount.minus(takerAssetFillAmount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('getOrderRelevantStates', async () => {
|
||||||
|
it('should return the correct information for multiple orders', async () => {
|
||||||
|
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||||
|
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||||
|
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||||
|
from: makerAddress,
|
||||||
|
});
|
||||||
|
const signedOrder2 = await orderFactory.newSignedOrderAsync({ makerAssetData: erc721AssetData });
|
||||||
|
const invalidSignature = '0x01';
|
||||||
|
await exchange.cancelOrder.awaitTransactionSuccessAsync(signedOrder2, { from: makerAddress });
|
||||||
|
const [
|
||||||
|
ordersInfo,
|
||||||
|
fillableTakerAssetAmounts,
|
||||||
|
isValidSignature,
|
||||||
|
] = await devUtils.getOrderRelevantStates.callAsync(
|
||||||
|
[signedOrder, signedOrder2],
|
||||||
|
[signedOrder.signature, invalidSignature],
|
||||||
|
);
|
||||||
|
expect(ordersInfo[0].orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder));
|
||||||
|
expect(ordersInfo[1].orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder2));
|
||||||
|
expect(ordersInfo[0].orderStatus).to.equal(OrderStatus.Fillable);
|
||||||
|
expect(ordersInfo[1].orderStatus).to.equal(OrderStatus.Cancelled);
|
||||||
|
expect(ordersInfo[0].orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
expect(ordersInfo[1].orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
expect(fillableTakerAssetAmounts[0]).to.bignumber.equal(signedOrder.takerAssetAmount);
|
||||||
|
expect(fillableTakerAssetAmounts[1]).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
expect(isValidSignature[0]).to.equal(true);
|
||||||
|
expect(isValidSignature[1]).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// tslint:disable:max-file-line-count
|
12
contracts/dev-utils/tsconfig.json
Normal file
12
contracts/dev-utils/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||||
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
|
"files": [
|
||||||
|
"generated-artifacts/DevUtils.json",
|
||||||
|
"generated-artifacts/LibAssetData.json",
|
||||||
|
"generated-artifacts/LibTransactionDecoder.json",
|
||||||
|
"generated-artifacts/EthBalanceChecker.json"
|
||||||
|
],
|
||||||
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
}
|
6
contracts/dev-utils/tslint.json
Normal file
6
contracts/dev-utils/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": ["@0x/tslint-config"],
|
||||||
|
"rules": {
|
||||||
|
"custom-no-magic-numbers": false
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,67 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "1.1.8",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1563006338,
|
||||||
|
"version": "1.1.7",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1558712885,
|
||||||
|
"version": "1.1.6",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557961111,
|
||||||
|
"version": "1.1.5",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.1.4",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1557799313
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557507213,
|
||||||
|
"version": "1.1.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.1.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1554997931
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.1.8 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.1.7 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.1.6 - _May 24, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.1.5 - _May 15, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.1.4 - _May 14, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.1.2 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.1.1 - _April 11, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.1.0 - _March 21, 2019_
|
## v1.1.0 - _March 21, 2019_
|
||||||
|
|
||||||
* Run Web3ProviderEngine without excess block polling (#1695)
|
* Run Web3ProviderEngine without excess block polling (#1695)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "generated-artifacts",
|
"artifactsDir": "generated-artifacts",
|
||||||
"contractsDir": "contracts",
|
"contractsDir": "contracts",
|
||||||
"useDockerisedSolc": true,
|
"useDockerisedSolc": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "constantinople",
|
||||||
"optimizer": { "enabled": true, "runs": 1000000 },
|
"optimizer": { "enabled": true, "runs": 1000000 },
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
"abi",
|
"abi",
|
||||||
|
"devdoc",
|
||||||
"evm.bytecode.object",
|
"evm.bytecode.object",
|
||||||
"evm.bytecode.sourceMap",
|
"evm.bytecode.sourceMap",
|
||||||
"evm.deployedBytecode.object",
|
"evm.deployedBytecode.object",
|
||||||
|
@@ -63,6 +63,32 @@ contract ERC1155Mintable is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev creates a new token
|
||||||
|
/// @param type_ of token
|
||||||
|
/// @param uri URI of token
|
||||||
|
function createWithType(
|
||||||
|
uint256 type_,
|
||||||
|
string calldata uri
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
// This will allow restricted access to creators.
|
||||||
|
creators[type_] = msg.sender;
|
||||||
|
|
||||||
|
// emit a Transfer event with Create semantic to help with discovery.
|
||||||
|
emit TransferSingle(
|
||||||
|
msg.sender,
|
||||||
|
address(0x0),
|
||||||
|
address(0x0),
|
||||||
|
type_,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bytes(uri).length > 0) {
|
||||||
|
emit URI(uri, type_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev mints fungible tokens
|
/// @dev mints fungible tokens
|
||||||
/// @param id token type
|
/// @param id token type
|
||||||
/// @param to beneficiaries of minted tokens
|
/// @param to beneficiaries of minted tokens
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc1155",
|
"name": "@0x/contracts-erc1155",
|
||||||
"version": "1.1.0",
|
"version": "1.1.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
"coverage:report:text": "istanbul report text",
|
"coverage:report:text": "istanbul report text",
|
||||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
@@ -46,11 +47,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^2.0.8",
|
"@0x/abi-gen": "^2.1.1",
|
||||||
"@0x/contracts-gen": "^1.0.7",
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
"@0x/dev-utils": "^2.2.0",
|
"@0x/dev-utils": "^2.2.4",
|
||||||
"@0x/sol-compiler": "^3.1.5",
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
"@0x/tslint-config": "^3.0.0",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@@ -66,14 +67,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.4",
|
"@0x/base-contract": "^5.1.1",
|
||||||
"@0x/contracts-test-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
"@0x/contracts-utils": "^3.1.0",
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
"@0x/types": "^2.2.1",
|
"@0x/types": "^2.4.0",
|
||||||
"@0x/typescript-typings": "^4.2.1",
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
"@0x/utils": "^4.3.0",
|
"@0x/utils": "^4.4.0",
|
||||||
"@0x/web3-wrapper": "^6.0.4",
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
"ethereum-types": "^2.1.1",
|
"ethereum-types": "^2.1.3",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@@ -36,8 +36,8 @@ export class Erc1155Wrapper {
|
|||||||
callbackData?: string,
|
callbackData?: string,
|
||||||
delegatedSpender?: string,
|
delegatedSpender?: string,
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const spender = _.isUndefined(delegatedSpender) ? from : delegatedSpender;
|
const spender = delegatedSpender === undefined ? from : delegatedSpender;
|
||||||
const callbackDataHex = _.isUndefined(callbackData) ? '0x' : callbackData;
|
const callbackDataHex = callbackData === undefined ? '0x' : callbackData;
|
||||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(
|
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(
|
||||||
await this._erc1155Contract.safeTransferFrom.sendTransactionAsync(from, to, token, value, callbackDataHex, {
|
await this._erc1155Contract.safeTransferFrom.sendTransactionAsync(from, to, token, value, callbackDataHex, {
|
||||||
from: spender,
|
from: spender,
|
||||||
@@ -53,8 +53,8 @@ export class Erc1155Wrapper {
|
|||||||
callbackData?: string,
|
callbackData?: string,
|
||||||
delegatedSpender?: string,
|
delegatedSpender?: string,
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const spender = _.isUndefined(delegatedSpender) ? from : delegatedSpender;
|
const spender = delegatedSpender === undefined ? from : delegatedSpender;
|
||||||
const callbackDataHex = _.isUndefined(callbackData) ? '0x' : callbackData;
|
const callbackDataHex = callbackData === undefined ? '0x' : callbackData;
|
||||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(
|
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(
|
||||||
await this._erc1155Contract.safeBatchTransferFrom.sendTransactionAsync(
|
await this._erc1155Contract.safeBatchTransferFrom.sendTransactionAsync(
|
||||||
from,
|
from,
|
||||||
|
@@ -1,4 +1,68 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "2.2.7",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1563006338,
|
||||||
|
"version": "2.2.6",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1558712885,
|
||||||
|
"version": "2.2.5",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557961111,
|
||||||
|
"version": "2.2.4",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.2.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1557799313
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557507213,
|
||||||
|
"version": "2.2.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.2.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Added UntransferrableDummyERC20Token",
|
||||||
|
"pr": 1714
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1554997931
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.2.7 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.6 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.5 - _May 24, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.4 - _May 15, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.3 - _May 14, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.1 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.2.0 - _April 11, 2019_
|
||||||
|
|
||||||
|
* Added UntransferrableDummyERC20Token (#1714)
|
||||||
|
|
||||||
## v2.1.0 - _March 21, 2019_
|
## v2.1.0 - _March 21, 2019_
|
||||||
|
|
||||||
* Run Web3ProviderEngine without excess block polling (#1695)
|
* Run Web3ProviderEngine without excess block polling (#1695)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "./generated-artifacts",
|
"artifactsDir": "./generated-artifacts",
|
||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": true,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "constantinople",
|
||||||
@@ -14,10 +14,12 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
"abi",
|
"abi",
|
||||||
|
"devdoc",
|
||||||
"evm.bytecode.object",
|
"evm.bytecode.object",
|
||||||
"evm.bytecode.sourceMap",
|
"evm.bytecode.sourceMap",
|
||||||
"evm.deployedBytecode.object",
|
"evm.deployedBytecode.object",
|
||||||
"evm.deployedBytecode.sourceMap"
|
"evm.deployedBytecode.sourceMap",
|
||||||
|
"devdoc"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
"src/interfaces/IEtherToken.sol",
|
"src/interfaces/IEtherToken.sol",
|
||||||
"test/DummyERC20Token.sol",
|
"test/DummyERC20Token.sol",
|
||||||
"test/DummyMultipleReturnERC20Token.sol",
|
"test/DummyMultipleReturnERC20Token.sol",
|
||||||
"test/DummyNoReturnERC20Token.sol"
|
"test/DummyNoReturnERC20Token.sol",
|
||||||
|
"test/UntransferrableDummyERC20Token.sol"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
import "./DummyERC20Token.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable no-empty-blocks
|
||||||
|
contract UntransferrableDummyERC20Token is
|
||||||
|
DummyERC20Token
|
||||||
|
{
|
||||||
|
constructor (
|
||||||
|
string memory _name,
|
||||||
|
string memory _symbol,
|
||||||
|
uint256 _decimals,
|
||||||
|
uint256 _totalSupply
|
||||||
|
)
|
||||||
|
public
|
||||||
|
DummyERC20Token(
|
||||||
|
_name,
|
||||||
|
_symbol,
|
||||||
|
_decimals,
|
||||||
|
_totalSupply
|
||||||
|
)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
|
||||||
|
/// @param _from The address of the sender
|
||||||
|
/// @param _to The address of the recipient
|
||||||
|
/// @param _value The amount of token to be transferred
|
||||||
|
function transferFrom(
|
||||||
|
address _from,
|
||||||
|
address _to,
|
||||||
|
uint256 _value
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
require(
|
||||||
|
false,
|
||||||
|
"TRANSFER_DISABLED"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc20",
|
"name": "@0x/contracts-erc20",
|
||||||
"version": "2.1.0",
|
"version": "2.2.7",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
"coverage:report:text": "istanbul report text",
|
"coverage:report:text": "istanbul report text",
|
||||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
@@ -46,12 +47,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^2.0.8",
|
"@0x/abi-gen": "^2.1.1",
|
||||||
"@0x/contracts-gen": "^1.0.7",
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
"@0x/contracts-test-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
"@0x/dev-utils": "^2.2.0",
|
"@0x/dev-utils": "^2.2.4",
|
||||||
"@0x/sol-compiler": "^3.1.5",
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
"@0x/tslint-config": "^3.0.0",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@@ -67,14 +68,13 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.4",
|
"@0x/base-contract": "^5.1.1",
|
||||||
"@0x/contracts-exchange-libs": "^2.1.0",
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
"@0x/contracts-utils": "^3.1.0",
|
"@0x/types": "^2.4.0",
|
||||||
"@0x/types": "^2.2.1",
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
"@0x/typescript-typings": "^4.2.1",
|
"@0x/utils": "^4.4.0",
|
||||||
"@0x/utils": "^4.3.0",
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
"@0x/web3-wrapper": "^6.0.4",
|
"ethereum-types": "^2.1.3",
|
||||||
"ethereum-types": "^2.1.1",
|
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@@ -1,4 +1,67 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "2.1.8",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1563006338,
|
||||||
|
"version": "2.1.7",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1558712885,
|
||||||
|
"version": "2.1.6",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557961111,
|
||||||
|
"version": "2.1.5",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.1.4",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1557799313
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557507213,
|
||||||
|
"version": "2.1.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.1.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1554997931
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.1.8 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.7 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.6 - _May 24, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.5 - _May 15, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.4 - _May 14, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.2 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v2.1.1 - _April 11, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v2.1.0 - _March 21, 2019_
|
## v2.1.0 - _March 21, 2019_
|
||||||
|
|
||||||
* Run Web3ProviderEngine without excess block polling (#1695)
|
* Run Web3ProviderEngine without excess block polling (#1695)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "./generated-artifacts",
|
"artifactsDir": "./generated-artifacts",
|
||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": true,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "constantinople",
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
"abi",
|
"abi",
|
||||||
|
"devdoc",
|
||||||
"evm.bytecode.object",
|
"evm.bytecode.object",
|
||||||
"evm.bytecode.sourceMap",
|
"evm.bytecode.sourceMap",
|
||||||
"evm.deployedBytecode.object",
|
"evm.deployedBytecode.object",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc721",
|
"name": "@0x/contracts-erc721",
|
||||||
"version": "2.1.0",
|
"version": "2.1.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
"coverage:report:text": "istanbul report text",
|
"coverage:report:text": "istanbul report text",
|
||||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
@@ -46,12 +47,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^2.0.8",
|
"@0x/abi-gen": "^2.1.1",
|
||||||
"@0x/contracts-gen": "^1.0.7",
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
"@0x/contracts-test-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
"@0x/dev-utils": "^2.2.0",
|
"@0x/dev-utils": "^2.2.4",
|
||||||
"@0x/sol-compiler": "^3.1.5",
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
"@0x/tslint-config": "^3.0.0",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@@ -67,13 +68,13 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.4",
|
"@0x/base-contract": "^5.1.1",
|
||||||
"@0x/contracts-utils": "^3.1.0",
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
"@0x/types": "^2.2.1",
|
"@0x/types": "^2.4.0",
|
||||||
"@0x/typescript-typings": "^4.2.1",
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
"@0x/utils": "^4.3.0",
|
"@0x/utils": "^4.4.0",
|
||||||
"@0x/web3-wrapper": "^6.0.4",
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
"ethereum-types": "^2.1.1",
|
"ethereum-types": "^2.1.3",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@@ -1,4 +1,68 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1563047529,
|
||||||
|
"version": "3.0.5",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1563006338,
|
||||||
|
"version": "3.0.4",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1558712885,
|
||||||
|
"version": "3.0.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557961111,
|
||||||
|
"version": "3.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1557799313,
|
||||||
|
"version": "3.0.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "3.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Update contracts to solidity ^0.5.5 and unpin dependencies",
|
||||||
|
"pr": 1796
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1557507213
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2.1.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1554997931
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.0.5 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v3.0.4 - _July 13, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v3.0.3 - _May 24, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v3.0.2 - _May 15, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v3.0.1 - _May 14, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v3.0.0 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Update contracts to solidity ^0.5.5 and unpin dependencies (#1796)
|
||||||
|
|
||||||
|
## v2.1.1 - _April 11, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v2.1.0 - _March 21, 2019_
|
## v2.1.0 - _March 21, 2019_
|
||||||
|
|
||||||
* Run Web3ProviderEngine without excess block polling (#1695)
|
* Run Web3ProviderEngine without excess block polling (#1695)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "./generated-artifacts",
|
"artifactsDir": "./generated-artifacts",
|
||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": true,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "constantinople",
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
"abi",
|
"abi",
|
||||||
|
"devdoc",
|
||||||
"evm.bytecode.object",
|
"evm.bytecode.object",
|
||||||
"evm.bytecode.sourceMap",
|
"evm.bytecode.sourceMap",
|
||||||
"evm.deployedBytecode.object",
|
"evm.deployedBytecode.object",
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./MixinWeth.sol";
|
import "./MixinWeth.sol";
|
||||||
@@ -40,6 +40,7 @@ contract Forwarder is
|
|||||||
bytes memory _wethAssetData
|
bytes memory _wethAssetData
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
|
Ownable()
|
||||||
LibConstants(
|
LibConstants(
|
||||||
_exchange,
|
_exchange,
|
||||||
_zrxAssetData,
|
_zrxAssetData,
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||||
@@ -35,13 +35,13 @@ contract MixinAssets is
|
|||||||
|
|
||||||
bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
|
bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
|
||||||
|
|
||||||
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||||
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||||
/// used to withdraw assets that were accidentally sent to this contract.
|
/// used to withdraw assets that were accidentally sent to this contract.
|
||||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
/// @param amount Amount of ERC20 token to withdraw.
|
/// @param amount Amount of ERC20 token to withdraw.
|
||||||
function withdrawAsset(
|
function withdrawAsset(
|
||||||
bytes assetData,
|
bytes calldata assetData,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
@@ -84,7 +84,7 @@ contract MixinAssets is
|
|||||||
// Transfer tokens.
|
// Transfer tokens.
|
||||||
// We do a raw call so we can check the success separate
|
// We do a raw call so we can check the success separate
|
||||||
// from the return data.
|
// from the return data.
|
||||||
bool success = token.call(abi.encodeWithSelector(
|
(bool success,) = token.call(abi.encodeWithSelector(
|
||||||
ERC20_TRANSFER_SELECTOR,
|
ERC20_TRANSFER_SELECTOR,
|
||||||
msg.sender,
|
msg.sender,
|
||||||
amount
|
amount
|
||||||
@@ -93,7 +93,7 @@ contract MixinAssets is
|
|||||||
success,
|
success,
|
||||||
"TRANSFER_FAILED"
|
"TRANSFER_FAILED"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check return data.
|
// Check return data.
|
||||||
// If there is no return data, we assume the token incorrectly
|
// If there is no return data, we assume the token incorrectly
|
||||||
// does not return a bool. In this case we expect it to revert
|
// does not return a bool. In this case we expect it to revert
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
@@ -144,6 +144,7 @@ contract MixinExchangeWrapper is
|
|||||||
bytes memory wethAssetData = WETH_ASSET_DATA;
|
bytes memory wethAssetData = WETH_ASSET_DATA;
|
||||||
|
|
||||||
uint256 ordersLength = orders.length;
|
uint256 ordersLength = orders.length;
|
||||||
|
uint256 makerAssetFilledAmount = 0;
|
||||||
for (uint256 i = 0; i != ordersLength; i++) {
|
for (uint256 i = 0; i != ordersLength; i++) {
|
||||||
|
|
||||||
// We assume that asset being bought by taker is the same for each order.
|
// We assume that asset being bought by taker is the same for each order.
|
||||||
@@ -175,7 +176,7 @@ contract MixinExchangeWrapper is
|
|||||||
addFillResults(totalFillResults, singleFillResults);
|
addFillResults(totalFillResults, singleFillResults);
|
||||||
|
|
||||||
// Stop execution if the entire amount of makerAsset has been bought
|
// Stop execution if the entire amount of makerAsset has been bought
|
||||||
uint256 makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount;
|
makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount;
|
||||||
if (makerAssetFilledAmount >= makerAssetFillAmount) {
|
if (makerAssetFilledAmount >= makerAssetFillAmount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -192,7 +193,7 @@ contract MixinExchangeWrapper is
|
|||||||
/// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
|
/// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
|
||||||
/// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
|
/// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
|
||||||
/// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
|
/// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
|
||||||
/// The asset being sold by taker must always be WETH.
|
/// The asset being sold by taker must always be WETH.
|
||||||
/// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
|
/// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
|
||||||
/// @param zrxBuyAmount Desired amount of ZRX to buy.
|
/// @param zrxBuyAmount Desired amount of ZRX to buy.
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
@@ -230,7 +231,7 @@ contract MixinExchangeWrapper is
|
|||||||
// of the Maker. In this case we want to overestimate the amount of takerAsset.
|
// of the Maker. In this case we want to overestimate the amount of takerAsset.
|
||||||
uint256 remainingWethSellAmount = getPartialAmountCeil(
|
uint256 remainingWethSellAmount = getPartialAmountCeil(
|
||||||
orders[i].takerAssetAmount,
|
orders[i].takerAssetAmount,
|
||||||
safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
|
safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
|
||||||
remainingZrxBuyAmount
|
remainingZrxBuyAmount
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
@@ -58,7 +58,7 @@ contract MixinForwarderCore is
|
|||||||
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
||||||
/// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
|
/// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
|
||||||
/// Any ETH not spent will be refunded to sender.
|
/// Any ETH not spent will be refunded to sender.
|
||||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
||||||
/// @param feeSignatures Proofs that feeOrders have been created by makers.
|
/// @param feeSignatures Proofs that feeOrders have been created by makers.
|
||||||
@@ -70,8 +70,8 @@ contract MixinForwarderCore is
|
|||||||
bytes[] memory signatures,
|
bytes[] memory signatures,
|
||||||
LibOrder.Order[] memory feeOrders,
|
LibOrder.Order[] memory feeOrders,
|
||||||
bytes[] memory feeSignatures,
|
bytes[] memory feeSignatures,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
payable
|
payable
|
||||||
@@ -142,7 +142,7 @@ contract MixinForwarderCore is
|
|||||||
/// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
|
/// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
|
||||||
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
||||||
/// Any ETH not spent will be refunded to sender.
|
/// Any ETH not spent will be refunded to sender.
|
||||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
/// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
|
/// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
||||||
@@ -156,8 +156,8 @@ contract MixinForwarderCore is
|
|||||||
bytes[] memory signatures,
|
bytes[] memory signatures,
|
||||||
LibOrder.Order[] memory feeOrders,
|
LibOrder.Order[] memory feeOrders,
|
||||||
bytes[] memory feeSignatures,
|
bytes[] memory feeSignatures,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
payable
|
payable
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
@@ -30,7 +30,7 @@ contract MixinWeth is
|
|||||||
{
|
{
|
||||||
/// @dev Default payabale function, this allows us to withdraw WETH
|
/// @dev Default payabale function, this allows us to withdraw WETH
|
||||||
function ()
|
function ()
|
||||||
public
|
external
|
||||||
payable
|
payable
|
||||||
{
|
{
|
||||||
require(
|
require(
|
||||||
@@ -60,7 +60,7 @@ contract MixinWeth is
|
|||||||
uint256 wethSoldExcludingFeeOrders,
|
uint256 wethSoldExcludingFeeOrders,
|
||||||
uint256 wethSoldForZrx,
|
uint256 wethSoldForZrx,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
{
|
{
|
||||||
@@ -92,7 +92,7 @@ contract MixinWeth is
|
|||||||
ethFee <= wethRemaining,
|
ethFee <= wethRemaining,
|
||||||
"INSUFFICIENT_ETH_REMAINING"
|
"INSUFFICIENT_ETH_REMAINING"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Do nothing if no WETH remaining
|
// Do nothing if no WETH remaining
|
||||||
if (wethRemaining > 0) {
|
if (wethRemaining > 0) {
|
||||||
// Convert remaining WETH to ETH
|
// Convert remaining WETH to ETH
|
||||||
|
@@ -16,18 +16,18 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
|
||||||
contract IAssets {
|
contract IAssets {
|
||||||
|
|
||||||
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||||
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||||
/// used to withdraw assets that were accidentally sent to this contract.
|
/// used to withdraw assets that were accidentally sent to this contract.
|
||||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
/// @param amount Amount of ERC20 token to withdraw.
|
/// @param amount Amount of ERC20 token to withdraw.
|
||||||
function withdrawAsset(
|
function withdrawAsset(
|
||||||
bytes assetData,
|
bytes calldata assetData,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./IForwarderCore.sol";
|
import "./IForwarderCore.sol";
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
@@ -29,7 +29,7 @@ contract IForwarderCore {
|
|||||||
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
||||||
/// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
|
/// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
|
||||||
/// Any ETH not spent will be refunded to sender.
|
/// Any ETH not spent will be refunded to sender.
|
||||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
||||||
/// @param feeSignatures Proofs that feeOrders have been created by makers.
|
/// @param feeSignatures Proofs that feeOrders have been created by makers.
|
||||||
@@ -41,8 +41,8 @@ contract IForwarderCore {
|
|||||||
bytes[] memory signatures,
|
bytes[] memory signatures,
|
||||||
LibOrder.Order[] memory feeOrders,
|
LibOrder.Order[] memory feeOrders,
|
||||||
bytes[] memory feeSignatures,
|
bytes[] memory feeSignatures,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
payable
|
payable
|
||||||
@@ -54,7 +54,7 @@ contract IForwarderCore {
|
|||||||
/// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
|
/// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
|
||||||
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
/// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
|
||||||
/// Any ETH not spent will be refunded to sender.
|
/// Any ETH not spent will be refunded to sender.
|
||||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
/// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
|
/// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
/// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
|
||||||
@@ -68,8 +68,8 @@ contract IForwarderCore {
|
|||||||
bytes[] memory signatures,
|
bytes[] memory signatures,
|
||||||
LibOrder.Order[] memory feeOrders,
|
LibOrder.Order[] memory feeOrders,
|
||||||
bytes[] memory feeSignatures,
|
bytes[] memory feeSignatures,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
payable
|
payable
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
@@ -31,10 +31,10 @@ contract LibConstants {
|
|||||||
bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
|
bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||||
bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||||
uint256 constant internal MAX_UINT = 2**256 - 1;
|
uint256 constant internal MAX_UINT = 2**256 - 1;
|
||||||
uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
|
uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
|
||||||
uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
|
uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
|
||||||
uint256 constant internal MAX_WETH_FILL_PERCENTAGE = 95 * PERCENTAGE_DENOMINATOR / 100; // 95%
|
uint256 constant internal MAX_WETH_FILL_PERCENTAGE = 95 * PERCENTAGE_DENOMINATOR / 100; // 95%
|
||||||
|
|
||||||
// solhint-disable var-name-mixedcase
|
// solhint-disable var-name-mixedcase
|
||||||
IExchange internal EXCHANGE;
|
IExchange internal EXCHANGE;
|
||||||
IEtherToken internal ETHER_TOKEN;
|
IEtherToken internal ETHER_TOKEN;
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// solhint-disable
|
// solhint-disable
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
|
||||||
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
|
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../interfaces/IAssets.sol";
|
import "../interfaces/IAssets.sol";
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
@@ -72,7 +72,7 @@ contract MExchangeWrapper {
|
|||||||
/// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
|
/// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
|
||||||
/// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
|
/// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
|
||||||
/// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
|
/// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
|
||||||
/// The asset being sold by taker must always be WETH.
|
/// The asset being sold by taker must always be WETH.
|
||||||
/// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
|
/// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
|
||||||
/// @param zrxBuyAmount Desired amount of ZRX to buy.
|
/// @param zrxBuyAmount Desired amount of ZRX to buy.
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.4.24;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
|
||||||
contract MWeth {
|
contract MWeth {
|
||||||
@@ -35,7 +35,7 @@ contract MWeth {
|
|||||||
uint256 wethSoldExcludingFeeOrders,
|
uint256 wethSoldExcludingFeeOrders,
|
||||||
uint256 wethSoldForZrx,
|
uint256 wethSoldForZrx,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-exchange-forwarder",
|
"name": "@0x/contracts-exchange-forwarder",
|
||||||
"version": "2.1.0",
|
"version": "3.0.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -46,13 +46,13 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^2.0.8",
|
"@0x/abi-gen": "^2.1.1",
|
||||||
"@0x/contract-wrappers": "^8.0.5",
|
"@0x/contract-wrappers": "^9.1.6",
|
||||||
"@0x/contracts-gen": "^1.0.7",
|
"@0x/contracts-gen": "^1.0.10",
|
||||||
"@0x/contracts-test-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.9",
|
||||||
"@0x/dev-utils": "^2.2.0",
|
"@0x/dev-utils": "^2.2.4",
|
||||||
"@0x/sol-compiler": "^3.1.5",
|
"@0x/sol-compiler": "^3.1.9",
|
||||||
"@0x/tslint-config": "^3.0.0",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@@ -68,19 +68,19 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.4",
|
"@0x/base-contract": "^5.1.1",
|
||||||
"@0x/contracts-asset-proxy": "^2.1.0",
|
"@0x/contracts-asset-proxy": "^2.2.1",
|
||||||
"@0x/contracts-erc20": "1.0.8",
|
"@0x/contracts-erc20": "^2.2.7",
|
||||||
"@0x/contracts-erc721": "1.0.8",
|
"@0x/contracts-erc721": "^2.1.8",
|
||||||
"@0x/contracts-exchange": "1.0.2",
|
"@0x/contracts-exchange": "^2.1.7",
|
||||||
"@0x/contracts-exchange-libs": "1.0.2",
|
"@0x/contracts-exchange-libs": "^3.0.1",
|
||||||
"@0x/contracts-utils": "2.0.1",
|
"@0x/contracts-utils": "^3.1.8",
|
||||||
"@0x/order-utils": "^7.1.1",
|
"@0x/order-utils": "^8.2.1",
|
||||||
"@0x/types": "^2.2.1",
|
"@0x/types": "^2.4.0",
|
||||||
"@0x/typescript-typings": "^4.2.1",
|
"@0x/typescript-typings": "^4.2.3",
|
||||||
"@0x/utils": "^4.3.0",
|
"@0x/utils": "^4.4.0",
|
||||||
"@0x/web3-wrapper": "^6.0.4",
|
"@0x/web3-wrapper": "^6.0.7",
|
||||||
"ethereum-types": "^2.1.1",
|
"ethereum-types": "^2.1.3",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@@ -89,7 +89,7 @@ describe(ContractName.Forwarder, () => {
|
|||||||
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
||||||
|
|
||||||
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(erc20Artifacts.WETH9, provider, txDefaults);
|
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(erc20Artifacts.WETH9, provider, txDefaults);
|
||||||
weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider);
|
weth = new DummyERC20TokenContract(wethContract.address, provider);
|
||||||
erc20Wrapper.addDummyTokenContract(weth);
|
erc20Wrapper.addDummyTokenContract(weth);
|
||||||
|
|
||||||
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
||||||
@@ -135,7 +135,7 @@ describe(ContractName.Forwarder, () => {
|
|||||||
zrxAssetData,
|
zrxAssetData,
|
||||||
wethAssetData,
|
wethAssetData,
|
||||||
);
|
);
|
||||||
forwarderContract = new ForwarderContract(forwarderInstance.abi, forwarderInstance.address, provider);
|
forwarderContract = new ForwarderContract(forwarderInstance.address, provider);
|
||||||
forwarderWrapper = new ForwarderWrapper(forwarderContract, provider);
|
forwarderWrapper = new ForwarderWrapper(forwarderContract, provider);
|
||||||
const zrxDepositAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18);
|
const zrxDepositAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user