Compare commits
495 Commits
protocol@6
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
9d42af7dd9 | ||
|
48cc9d2dc1 | ||
|
ec336b92aa | ||
|
62a530d7ec | ||
|
09d6fbce81 | ||
|
7f324dd75d | ||
|
bd02e7b3d5 | ||
|
e1f9e107e9 | ||
|
3c98225720 | ||
|
19e0c3364a | ||
|
43e3dce965 | ||
|
9da449ec32 | ||
|
33ece5aa99 | ||
|
262d2a8089 | ||
|
51fa55badd | ||
|
f59d2438b0 | ||
|
8c9917bf03 | ||
|
b9e80db170 | ||
|
01e2690b2b | ||
|
4835a1b1e7 | ||
|
21c8477062 | ||
|
defdff460a | ||
|
fd68edb239 | ||
|
e5e1393f0e | ||
|
20961ef42e | ||
|
34febd728a | ||
|
fcdebe6b01 | ||
|
c2aed76f2f | ||
|
198d986fdc | ||
|
e2e1d1074c | ||
|
6a15dc3f13 | ||
|
c4a83f211f | ||
|
fefa3c13f6 | ||
|
f1d096a8af | ||
|
394ccbdc24 | ||
|
5a47f04ffc | ||
|
3c414c12e6 | ||
|
d268a1136c | ||
|
e086caa94b | ||
|
f8dd7168ee | ||
|
527ccf2ae5 | ||
|
a7acf2951d | ||
|
53e83e74e2 | ||
|
e57fc60a76 | ||
|
4379e15a4d | ||
|
b0c37606a8 | ||
|
da8e43adfe | ||
|
b483805a22 | ||
|
ff104e7505 | ||
|
8a2305c7b9 | ||
|
d7bc0b79df | ||
|
ad2d41fd90 | ||
|
721b984bbc | ||
|
72433ea5b7 | ||
|
f919e8ef02 | ||
|
dbcc7dd6f4 | ||
|
33b7515734 | ||
|
0179320e55 | ||
|
f96b944cce | ||
|
0fbdc1dccd | ||
|
484d9cafc4 | ||
|
e73885c9a0 | ||
|
948b17e2ed | ||
|
2b13dcfc14 | ||
|
d2bea4aa46 | ||
|
dc926a05b3 | ||
|
5cc53597de | ||
|
57ca2c07bb | ||
|
b0d2dee84d | ||
|
1422ad756d | ||
|
9d216f9c1c | ||
|
ff74738178 | ||
|
fe4fe48021 | ||
|
356e74a645 | ||
|
70590e3e56 | ||
|
4e0b671bd8 | ||
|
ea2ca700c3 | ||
|
3574ea5b27 | ||
|
b7bf5b5dfe | ||
|
cfbb9c6f6c | ||
|
7e40dd1826 | ||
|
bcbfbfa16c | ||
|
03fc744bbd | ||
|
a23143d1eb | ||
|
c0ef6fece3 | ||
|
03ea4e3dba | ||
|
3e939f7780 | ||
|
d97dab83cd | ||
|
f0a4f6aeca | ||
|
f8a183812e | ||
|
f6fd374590 | ||
|
09763bcf5e | ||
|
3ab12ed254 | ||
|
25731653ef | ||
|
ec82c42c1b | ||
|
38665ffc86 | ||
|
459fb3ee28 | ||
|
dc8ff32d51 | ||
|
9f30823d70 | ||
|
f2f835591e | ||
|
8c35931041 | ||
|
a8539aa66e | ||
|
4d7df00d5a | ||
|
80193215e3 | ||
|
c4b1f043c6 | ||
|
a472125c65 | ||
|
8666121bd9 | ||
|
8cf1c8bbd2 | ||
|
d2abe9ad97 | ||
|
f8b65bd429 | ||
|
3a7a5d22a2 | ||
|
f87f5a40c0 | ||
|
5571d1698d | ||
|
6f7a7a7291 | ||
|
b613de1547 | ||
|
6fd269db34 | ||
|
033db23929 | ||
|
891d173705 | ||
|
091a10676c | ||
|
0ae6f3e64f | ||
|
8197fee50a | ||
|
ee48d4006b | ||
|
d2be56c30f | ||
|
c4097e4203 | ||
|
8f21d167cc | ||
|
b33fc27220 | ||
|
dcb17768cc | ||
|
82907f99a2 | ||
|
2e157cc307 | ||
|
3164d7882c | ||
|
91587efe2e | ||
|
008f00ba2f | ||
|
0e38b0e54a | ||
|
f6af4abd67 | ||
|
6dc3084c30 | ||
|
fd1f7a8a42 | ||
|
3a03174a92 | ||
|
f5e34bce3b | ||
|
3f8dbf3fe9 | ||
|
b040e55202 | ||
|
fe0676cec3 | ||
|
b697202e19 | ||
|
09bc48671c | ||
|
d31cc43ed6 | ||
|
372f23156b | ||
|
010a926d79 | ||
|
0000143b4e | ||
|
22684ff5ba | ||
|
4d9b68d527 | ||
|
957853788d | ||
|
28193479c6 | ||
|
70212534a1 | ||
|
ea9575e94d | ||
|
ca0b074893 | ||
|
b3281bfdb1 | ||
|
1516bf6a24 | ||
|
ab19bb41c4 | ||
|
7368aded88 | ||
|
b1f856e7a4 | ||
|
9d42018fc6 | ||
|
624cbebe27 | ||
|
4ace7c8c43 | ||
|
66846c8aec | ||
|
33e38fd0a1 | ||
|
5a6df5a39a | ||
|
592e7d34c9 | ||
|
1776dbef44 | ||
|
089718df33 | ||
|
7500ac36de | ||
|
f347f4392c | ||
|
10af74e616 | ||
|
cfb2392ac7 | ||
|
5a2447bef3 | ||
|
bf1b5c4257 | ||
|
10916205ab | ||
|
69f8fd39f7 | ||
|
0cc2cdd16e | ||
|
d207a4267e | ||
|
e846ed2f34 | ||
|
b04455c36f | ||
|
d06f6c8b4d | ||
|
a689e98b0f | ||
|
6f72a8e8e3 | ||
|
422f83fc99 | ||
|
b6597df84f | ||
|
c9b1aac8a5 | ||
|
87f4189e93 | ||
|
390e1b8510 | ||
|
5645e87aca | ||
|
0daa988996 | ||
|
b4d6f74d7b | ||
|
2163cb221b | ||
|
4575300016 | ||
|
82341c3b9d | ||
|
f89c2d2fed | ||
|
09419a7909 | ||
|
1fa093be64 | ||
|
8e9f358a02 | ||
|
0a2e8fc224 | ||
|
5653ee8f86 | ||
|
d180d5325d | ||
|
d249042b47 | ||
|
d3a6f79015 | ||
|
8c9dc96e5d | ||
|
fc0edba46b | ||
|
37dc99181e | ||
|
6efb9f532b | ||
|
9b7d88e136 | ||
|
e51e1f1674 | ||
|
036a263267 | ||
|
1fb44a55b4 | ||
|
d738eede0e | ||
|
a99c916100 | ||
|
2abb00b5e2 | ||
|
ef723e6f36 | ||
|
1fc139886e | ||
|
2be10bc72f | ||
|
abdc02f066 | ||
|
b7ef5473cd | ||
|
e43cdda22f | ||
|
416f2ec24c | ||
|
4f7fe66d74 | ||
|
eb394383d8 | ||
|
92e681f21b | ||
|
3f65dd6049 | ||
|
4425c316a3 | ||
|
9058839645 | ||
|
46a7a2e620 | ||
|
b35dccd43d | ||
|
08e0c2ebb9 | ||
|
8aa313a437 | ||
|
8e9699c340 | ||
|
939b708e63 | ||
|
1617e3fc44 | ||
|
e0d705703d | ||
|
01a6d933ca | ||
|
9b9f0b91d7 | ||
|
0d0fef841d | ||
|
17adfbea32 | ||
|
80594622b2 | ||
|
0dba5a5a3a | ||
|
4dae8de1b6 | ||
|
0046bb26d8 | ||
|
fe935f787c | ||
|
1b527ffcd8 | ||
|
9f5324d9c3 | ||
|
3647392a04 | ||
|
1d49662c58 | ||
|
6324b08b4d | ||
|
fe73b63aaa | ||
|
192d0b17d9 | ||
|
aa74d04083 | ||
|
d586f5727d | ||
|
98fc79a085 | ||
|
c12a10b96e | ||
|
d3d4a08f91 | ||
|
9ce090c8cd | ||
|
980d60deb8 | ||
|
d6d79e51e7 | ||
|
3ef5de93bb | ||
|
ab7dc33ca4 | ||
|
14dcee5bb6 | ||
|
9856e78609 | ||
|
2801b066b3 | ||
|
5bc8b13fc3 | ||
|
36dba8f5be | ||
|
ee2c069889 | ||
|
6ca14ed7b2 | ||
|
a5babb9a34 | ||
|
661cc4669d | ||
|
553ba5c868 | ||
|
d03d2f254d | ||
|
feb91a04b0 | ||
|
4d63f33aba | ||
|
b72b8b5ffd | ||
|
f7cb7a0f51 | ||
|
9fcb28f5d8 | ||
|
982173471c | ||
|
e77958425f | ||
|
6af4d71573 | ||
|
ee985240fb | ||
|
2aadbda527 | ||
|
297c73abcc | ||
|
4c9e1b21ec | ||
|
41685d1545 | ||
|
b9c25112ed | ||
|
f0738fc122 | ||
|
42baf504b7 | ||
|
56038d122f | ||
|
c4446b6c0e | ||
|
eaed2958c3 | ||
|
a045a3afb8 | ||
|
1cc59ab1ab | ||
|
2c6a714b71 | ||
|
d8c97d6720 | ||
|
d6bc702550 | ||
|
2838cb9420 | ||
|
b10cfc50d3 | ||
|
2e6317b01e | ||
|
50e99e6eac | ||
|
8f2f4554eb | ||
|
67d9678a3a | ||
|
f70341fb48 | ||
|
14cd24ea47 | ||
|
78328056d7 | ||
|
0045a60b0f | ||
|
e4e71c76e1 | ||
|
ca8127545f | ||
|
7b709089ce | ||
|
190f7e45f2 | ||
|
0dcc3a6fc3 | ||
|
c2e8cae293 | ||
|
83da7caab4 | ||
|
fd69a0c273 | ||
|
9b131199ad | ||
|
f5c486050b | ||
|
1f41fe6a20 | ||
|
7f4080e0a2 | ||
|
db76da58d7 | ||
|
cf8fc0ff8e | ||
|
2d16f83e37 | ||
|
4057bdab91 | ||
|
1cd10f0ac9 | ||
|
68f87b2432 | ||
|
69bafc3bcd | ||
|
2c44b06b7b | ||
|
0233f00b4e | ||
|
fedb53187d | ||
|
6774d2f588 | ||
|
cf740b74f5 | ||
|
177c00463a | ||
|
49b0e32129 | ||
|
938fc94756 | ||
|
1561d91c2b | ||
|
9a28e51f51 | ||
|
f55eaa867b | ||
|
6b2856424a | ||
|
da757c4700 | ||
|
75e6654884 | ||
|
87308e7693 | ||
|
d5eef93a76 | ||
|
a7f23a982e | ||
|
9eadc5fc28 | ||
|
92ad1a612e | ||
|
09413c0e12 | ||
|
23788b41d5 | ||
|
ccf999a495 | ||
|
aa1016ee5f | ||
|
423ef57344 | ||
|
c18149e82f | ||
|
d14aebf724 | ||
|
ba719a9631 | ||
|
d36034d958 | ||
|
7750c57620 | ||
|
4d027e11d1 | ||
|
470e9a4697 | ||
|
7c51412e2f | ||
|
b3d1f3cd10 | ||
|
389bb77439 | ||
|
4327885a00 | ||
|
0aef0afbbb | ||
|
fa4c3a4f5f | ||
|
1d7c527c5c | ||
|
cbe3135e4b | ||
|
955ad49711 | ||
|
8d6f6e76e0 | ||
|
9337115650 | ||
|
fa45a44fe4 | ||
|
c9c7ac8559 | ||
|
c881723578 | ||
|
c9c30d3a76 | ||
|
73dfdb5b69 | ||
|
e638268f94 | ||
|
0bfd765481 | ||
|
1f12893735 | ||
|
dd3d9337c4 | ||
|
904214f4a8 | ||
|
64c090c4b4 | ||
|
e24474f152 | ||
|
29fa408256 | ||
|
1b94cc68af | ||
|
f5b4bb3035 | ||
|
afd880f28c | ||
|
cd14cdd168 | ||
|
c8ff53a75f | ||
|
6d08add20b | ||
|
29f9c725e3 | ||
|
a83453f07f | ||
|
ae365ce92c | ||
|
77a592e891 | ||
|
9a1df67d6b | ||
|
4b91411faf | ||
|
622a542d57 | ||
|
cba53a9a50 | ||
|
e186f27f63 | ||
|
4cd767ecb8 | ||
|
f6e85aedf1 | ||
|
b3ee294ba5 | ||
|
1c242def93 | ||
|
f0fe6f2f69 | ||
|
f86d555e49 | ||
|
b0f2c40463 | ||
|
87be6fbb8a | ||
|
9141a9d2c8 | ||
|
7f75de347e | ||
|
329f7761c3 | ||
|
0d8e83cd75 | ||
|
e5d60b8077 | ||
|
ae2fe55efa | ||
|
6073607d3e | ||
|
389ebb5df8 | ||
|
fd9655e9d4 | ||
|
6480aaa189 | ||
|
38969bb0a8 | ||
|
1847ab93af | ||
|
c1177416f5 | ||
|
4fdd203211 | ||
|
4bc11776d7 | ||
|
eb12eac5f3 | ||
|
5f5b951998 | ||
|
8e90547604 | ||
|
fbea74d7ff | ||
|
dcea16bc13 | ||
|
d59a074bd7 | ||
|
39cc4f4dbf | ||
|
85bcf87af8 | ||
|
a0fe1c610f | ||
|
5d21af1a0a | ||
|
f6edbd210c | ||
|
e084807a8f | ||
|
1c7d512829 | ||
|
df0e0866e4 | ||
|
9e6efc3676 | ||
|
3aef29dace | ||
|
9a16e00577 | ||
|
84e4819e6e | ||
|
25dd6bc79a | ||
|
5d2cdb00c2 | ||
|
0f701f42d3 | ||
|
3e3e82d3f7 | ||
|
c57bf86273 | ||
|
f470d282ee | ||
|
b8a2526da5 | ||
|
97575bbde9 | ||
|
e5ed8b2c81 | ||
|
61fbae3ae2 | ||
|
5c2255c841 | ||
|
e036dee6c5 | ||
|
8583aab241 | ||
|
5d05b62821 | ||
|
0063e8178f | ||
|
ec6e5dd517 | ||
|
9d08fefa1c | ||
|
2fdca24d4e | ||
|
42ec0b144e | ||
|
3f6ce78b46 | ||
|
c1300c1068 | ||
|
9a641cfab6 | ||
|
60345d4465 | ||
|
11dfea47a6 | ||
|
55e9dd39a2 | ||
|
1993929bed | ||
|
e1d81de517 | ||
|
a6b3a21635 | ||
|
fd59cdc2db | ||
|
98e11b5189 | ||
|
3bebc7cd62 | ||
|
56dab6ae8c | ||
|
285f98e9e9 | ||
|
8ae9f59f20 | ||
|
4c341c5ca3 | ||
|
a3c912c2af | ||
|
5e72eb9af9 | ||
|
9b08b73c06 | ||
|
76c7eb7c3e | ||
|
9b2e5a3adb | ||
|
813d703d12 | ||
|
83005d0f3d | ||
|
d07ffd2688 | ||
|
4170f970d0 | ||
|
dcde12dd70 | ||
|
84a60ec982 | ||
|
9615570dc6 | ||
|
880a9c3da0 | ||
|
c44bd9d42d | ||
|
90b441330b | ||
|
e12ed1eddf | ||
|
ac94023ab3 | ||
|
281e6acca5 | ||
|
2f1b520409 | ||
|
21b4eb3d26 | ||
|
644f6c7d28 | ||
|
0647b9e4f8 | ||
|
82d42eeede | ||
|
6ef4d95043 |
@@ -1,209 +0,0 @@
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
resource_class: xlarge
|
||||
docker:
|
||||
- image: node:12
|
||||
environment:
|
||||
NODE_OPTIONS: '--max-old-space-size=16384'
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
- run:
|
||||
name: install-yarn
|
||||
command: npm install --force --global yarn@1.22.0
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||
- setup_remote_docker
|
||||
- run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
|
||||
- run: yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts
|
||||
- save_cache:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/abi-gen/test-cli/output
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/contract-wrappers/generated_docs
|
||||
test-exchange-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun -p @0x/contracts-exchange -m --serial -c test:circleci
|
||||
test-integrations-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun -p @0x/contracts-integrations -m --serial -c test:circleci
|
||||
test-contracts-staking-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun -p @0x/contracts-staking -m --serial -c test:circleci
|
||||
test-contracts-extra-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun -p @0x/contracts-exchange-forwarder -p @0x/contracts-coordinator -m --serial -c test:circleci
|
||||
test-contracts-rest-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun -p @0x/contracts-multisig -p @0x/contracts-utils -p @0x/contracts-exchange-libs -p @0x/contracts-erc20 -p @0x/contracts-erc721 -p @0x/contracts-erc1155 -p @0x/contracts-asset-proxy -p @0x/contracts-broker -p @0x/contracts-zero-ex -m --serial -c test:circleci
|
||||
test-publish:
|
||||
resource_class: large
|
||||
environment:
|
||||
NODE_OPTIONS: '--max-old-space-size=6442'
|
||||
docker:
|
||||
- image: node:12
|
||||
- image: 0xorg/verdaccio
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: yarn test:publish:circleci
|
||||
no_output_timeout: 1800
|
||||
- store_artifacts:
|
||||
path: ~/.npm/_logs
|
||||
test-doc-generation:
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: yarn test:generate_docs:circleci
|
||||
no_output_timeout: 1200
|
||||
test-rest:
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun -p @0x/contracts-test-utils -m --serial -c test:circleci
|
||||
- run: yarn wsrun -p @0x/contract-artifacts -m --serial -c test:circleci
|
||||
- run: yarn wsrun -p @0x/contract-wrappers-test -m --serial -c test:circleci
|
||||
- run: yarn wsrun -p @0x/migrations -m --serial -c test:circleci
|
||||
- run: yarn wsrun -p @0x/order-utils -m --serial -c test:circleci
|
||||
- run: yarn wsrun -p @0x/asset-swapper -m --serial -c test:circleci
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contract-wrappers-test/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/order-utils/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/web3-wrapper/coverage/lcov.info
|
||||
static-tests:
|
||||
resource_class: large
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: node:12
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn lerna run lint
|
||||
- run: yarn prettier:ci
|
||||
- run: yarn deps_versions:ci
|
||||
- run: yarn diff_md_docs:ci
|
||||
submit-coverage:
|
||||
docker:
|
||||
- image: node:12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn report_coverage
|
||||
workflows:
|
||||
version: 2
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
# Disabled until we begin actively developing on these packages again.
|
||||
# - test-exchange-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-integrations-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-contracts-staking-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-contracts-extra-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
- test-contracts-rest-ganache:
|
||||
requires:
|
||||
- build
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
- static-tests:
|
||||
requires:
|
||||
- build
|
||||
- test-publish:
|
||||
requires:
|
||||
- build
|
||||
- test-doc-generation:
|
||||
requires:
|
||||
- build
|
||||
# Disabled until this repo has a coveralls API key
|
||||
# - submit-coverage:
|
||||
# requires:
|
||||
# # Disabled until we begin actively developing on these packages again.
|
||||
# # - test-exchange-ganache
|
||||
# # - test-integrations-ganache
|
||||
# # - test-contracts-staking-ganache
|
||||
# # - test-contracts-extra-ganache
|
||||
# - test-contracts-rest-ganache
|
||||
# - test-rest
|
||||
# - static-tests
|
18
.github/CODEOWNERS
vendored
Normal file
18
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# See https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# for more info about CODEOWNERS file
|
||||
|
||||
# It uses the same pattern rule for gitignore file
|
||||
|
||||
# https://git-scm.com/docs/gitignore#_pattern_format
|
||||
|
||||
# Dev tools & setup
|
||||
|
||||
.github/ @dekz
|
||||
packages/contract-addresses/ @dekz @dextracker @kyu-c
|
||||
packages/contract-artifacts/ @dekz
|
||||
packages/protocol-utils/ @dekz
|
||||
|
||||
# Protocol/smart contracts
|
||||
|
||||
contracts/ @dekz @dextracker
|
28
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
28
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
@@ -8,13 +8,13 @@ We welcome contributions from anyone on the internet and are grateful for even t
|
||||
2. Clone your fork
|
||||
3. Follow the [installation & build steps](https://github.com/0xProject/0x-tools#install-dependencies) in the repo's top-level README.
|
||||
4. Setup the recommended [Development Tooling](#development-tooling).
|
||||
5. Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure))
|
||||
5. Open a [draft PR](https://github.blog/2019-02-14-introducing-draft-pull-requests/) against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure))
|
||||
|
||||
Before removing the `[WIP]` tag and submitting the PR for review, make sure:
|
||||
Before making the PR "Ready for review", make sure:
|
||||
|
||||
- It passes our linter checks (`yarn lint`)
|
||||
- It is properly formatted with Prettier (`yarn prettier`)
|
||||
- It passes our continuous integration tests (See: [Enabling code coverage checks on your fork](#enabling-code-coverage-checks-on-your-fork) for instructions on getting the `submit-coverage` test to pass on forks)
|
||||
- It passes our continuous integration tests (See: [Enabling code coverage checks on your fork](#fix-submit-coverage-ci-failure) for instructions on getting the `submit-coverage` test to pass on forks)
|
||||
- You've created/updated the corresponding [CHANGELOG](#CHANGELOGs) entries.
|
||||
- Your changes have sufficient test coverage (e.g regression tests have been added for bug fixes)
|
||||
|
||||
@@ -59,16 +59,14 @@ We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text
|
||||
|
||||
#### Linter
|
||||
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) to keep our code-style consistent.
|
||||
We use [ESLint](https://eslint.org/docs/latest/) to keep our code-style consistent.
|
||||
|
||||
Use `yarn:lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
|
||||
|
||||
If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
|
||||
Use `yarn lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
|
||||
|
||||
Integrate it into your text editor:
|
||||
|
||||
- VSCode: [vscode-tslint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint)
|
||||
- Atom: [linter-tslint](https://atom.io/packages/linter-tslint)
|
||||
- VSCode: [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
||||
- Atom: [ESLint](https://atom.io/packages/eslint)
|
||||
|
||||
#### Auto-formatter
|
||||
|
||||
@@ -91,15 +89,3 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
|
||||
1. If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe.
|
||||
1. Our enum conventions coincide with the recommended TypeScript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
|
||||
1. All public, exported methods/functions/classes must have associated Javadoc-style comments.
|
||||
|
||||
### Fix `submit-coverage` CI failure
|
||||
|
||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`.
|
||||
|
||||
To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following:
|
||||
|
||||
1. Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier.
|
||||
2. Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-tools, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
|
||||
3. In CircleCI, configure your project to add an environment variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the `Repo Token` you copied in step 1.
|
||||
|
||||
Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance.
|
12
ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md
vendored
12
ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md
vendored
@@ -2,15 +2,13 @@
|
||||
|
||||
<!--- Before submitting please check to see if this issue was already reported -->
|
||||
|
||||
<!--- Prefix your issue title with the package name it relates to (e.g., `0x.js: ` or `general:`) -->
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
|
||||
<!--- If you're suggesting a package change/improvement, tell us how it should work -->
|
||||
|
||||
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo -->
|
||||
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo https://github.com/0xProject/ZEIPs -->
|
||||
|
||||
## Current Behavior
|
||||
|
||||
@@ -50,8 +48,8 @@
|
||||
| ------: | :------ |
|
||||
|
||||
<!-- For example:
|
||||
| `0x.js` | 2.0.4 |
|
||||
| `Exchange Contract` | v2 |
|
||||
| `protocol-utils` | 2.0.4 |
|
||||
| `Exchange Contract` | v3 |
|
||||
-->
|
||||
|
||||
| Network |
|
||||
@@ -60,6 +58,6 @@
|
||||
|
||||
<!-- For example:
|
||||
| mainnet |
|
||||
| kovan |
|
||||
| testrpc |
|
||||
| goerli |
|
||||
| development |
|
||||
-->
|
@@ -20,7 +20,6 @@
|
||||
|
||||
<!--- The following points should be used to indicate the progress of your PR. Put an `x` in all the boxes that apply right now, and come back over time and check them off as you make progress. If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
|
||||
- [ ] Prefix PR title with `[WIP]` if necessary.
|
||||
- [ ] Add tests to cover changes as needed.
|
||||
- [ ] Update documentation as needed.
|
||||
- [ ] Add new entries to the relevant CHANGELOG.jsons.
|
9
.github/autolabeler.yml
vendored
9
.github/autolabeler.yml
vendored
@@ -1,7 +1,2 @@
|
||||
python: ['python-packages']
|
||||
contracts: ['contracts']
|
||||
@0x/contract-addresses: ['packages/contract-addresses']
|
||||
@0x/migrations: ['packages/migrations']
|
||||
@0x/order-utils: ['packages/order-utils']
|
||||
@0x/contract-artifacts: ['packages/contract-artifacts']
|
||||
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||
documentation: ['docs']
|
||||
liquidity integrations: ['contracts/zero-ex/contracts/src/transformers']
|
||||
|
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: monthly
|
||||
target-branch: "development"
|
19
.github/stale.yml
vendored
19
.github/stale.yml
vendored
@@ -1,19 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 30
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 30
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed because no activity occured in 7 days after being marked as stale. If it's still relevant - feel free to reopen. Thank you
|
||||
for your contributions.
|
160
.github/workflows/ci.yml
vendored
Normal file
160
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
name: Continuous Integration
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- development
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and test
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
ARBITRUM_RPC_URL: ${{ secrets.ARBITRUM_RPC_URL }}
|
||||
AVALANCHE_RPC_URL: ${{ secrets.AVALANCHE_RPC_URL }}
|
||||
BSC_RPC_URL: ${{ secrets.BSC_RPC_URL }}
|
||||
FANTOM_RPC_URL: ${{ secrets.FANTOM_RPC_URL }}
|
||||
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
|
||||
OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }}
|
||||
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Add foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
- name: Build solution
|
||||
run: yarn build
|
||||
|
||||
- name: Lint typescript
|
||||
run: yarn lint:ts
|
||||
|
||||
- name: Lint solidity
|
||||
run: yarn lint:contracts
|
||||
|
||||
- name: Run prettier
|
||||
run: yarn prettier:ci
|
||||
|
||||
- name: Check dependent packages have consistent versions
|
||||
run: yarn deps_versions:ci
|
||||
|
||||
- name: Check diff in docs
|
||||
run: yarn diff_md_docs:ci
|
||||
|
||||
- name: Check for broken links in markdown files
|
||||
run: yarn test:links
|
||||
|
||||
- name: Test doc generation
|
||||
run: yarn test:generate_docs:ci
|
||||
|
||||
- name: Test @0x/contracts-*
|
||||
run: |
|
||||
yarn wsrun \
|
||||
-p @0x/contracts-multisig \
|
||||
-p @0x/contracts-utils \
|
||||
-p @0x/contracts-exchange-libs \
|
||||
-p @0x/contracts-erc721 \
|
||||
-p @0x/contracts-erc1155 \
|
||||
-p @0x/contracts-asset-proxy \
|
||||
-p @0x/contracts-broker \
|
||||
-p @0x/contracts-zero-ex \
|
||||
-m --serial -c test:ci
|
||||
|
||||
- name: Test local @0x/contracts-*
|
||||
run: |
|
||||
yarn wsrun \
|
||||
-p @0x/contracts-test-utils \
|
||||
-p @0x/contract-addresses \
|
||||
-p @0x/contract-artifacts \
|
||||
-p @0x/contract-wrappers-test \
|
||||
-p @0x/order-utils \
|
||||
-m --serial -c test:ci
|
||||
|
||||
- name: Run Forge build for erc20
|
||||
working-directory: contracts/erc20
|
||||
run: |
|
||||
forge --version
|
||||
forge build --sizes
|
||||
|
||||
- name: Run Forge tests for erc20
|
||||
working-directory: contracts/erc20
|
||||
run: |
|
||||
forge test -vvv --gas-report
|
||||
|
||||
- name: Run Forge coverage for erc20
|
||||
working-directory: contracts/erc20
|
||||
run: |
|
||||
forge coverage --report summary --report lcov
|
||||
|
||||
- name: Upload the coverage report to Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
base-path: ./contracts/erc20/
|
||||
path-to-lcov: ./contracts/erc20/lcov.info
|
||||
|
||||
- name: Run Forge build for zero-ex
|
||||
working-directory: contracts/zero-ex
|
||||
run: |
|
||||
forge --version
|
||||
forge build --sizes
|
||||
|
||||
- name: Run Forge tests for zero-ex
|
||||
working-directory: contracts/zero-ex
|
||||
run: |
|
||||
forge test -vvv --gas-report
|
||||
|
||||
- name: Run Forge coverage for zero-ex
|
||||
working-directory: contracts/zero-ex
|
||||
run: |
|
||||
forge coverage --report summary --report lcov
|
||||
|
||||
- name: Upload the coverage report to Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
base-path: ./contracts/zero-ex/
|
||||
path-to-lcov: ./contracts/zero-ex/lcov.info
|
||||
|
||||
- name: Check coverage threshold
|
||||
uses: VeryGoodOpenSource/very_good_coverage@v2
|
||||
with:
|
||||
path: ./contracts/zero-ex/lcov.info
|
||||
min_coverage: 6.98
|
||||
exclude: '**/tests'
|
||||
|
||||
- name: Run Forge build on governance contracts
|
||||
working-directory: ./contracts/governance
|
||||
run: |
|
||||
forge --version
|
||||
forge build --sizes
|
||||
|
||||
- name: Run Forge tests on governance contracts
|
||||
working-directory: ./contracts/governance
|
||||
run: |
|
||||
forge test -vvv --gas-report
|
||||
|
||||
- name: Run Forge coverage on governance contracts
|
||||
working-directory: ./contracts/governance
|
||||
run: |
|
||||
forge coverage --report lcov
|
||||
|
||||
- name: Upload the coverage report to Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
base-path: ./contracts/governance/
|
||||
path-to-lcov: ./contracts/governance/lcov.info
|
58
.github/workflows/publish.yml
vendored
58
.github/workflows/publish.yml
vendored
@@ -1,19 +1,21 @@
|
||||
name: publish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ci_status:
|
||||
description: 'required CI status'
|
||||
default: 'success'
|
||||
required: true
|
||||
prerelease:
|
||||
description: 'prerelease name'
|
||||
required: false
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ci_status:
|
||||
description: 'required CI status'
|
||||
default: 'success'
|
||||
required: true
|
||||
prerelease:
|
||||
description: 'prerelease name'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PublishBranch: publish/${{github.ref_name }}-${{ github.run_id }}-${{ github.run_number }}
|
||||
steps:
|
||||
- name: 'check successful status'
|
||||
run: |
|
||||
@@ -22,18 +24,26 @@ jobs:
|
||||
| jq .state)
|
||||
[[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \
|
||||
(echo "::error ::${{ github.ref }} does not have a successful CI status" && false)
|
||||
- name: Add foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }}
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 16
|
||||
- uses: actions/setup-python@v2
|
||||
- name: 'configure git'
|
||||
run: |
|
||||
git config --global user.email "github-actions@github.com"
|
||||
git config --global user.name "Github Actions"
|
||||
- name: 'Checkout new branch'
|
||||
run: |
|
||||
git checkout -b $PublishBranch
|
||||
git push -u origin $PublishBranch
|
||||
- name: 'install dependencies'
|
||||
run: |
|
||||
yarn -D
|
||||
@@ -45,9 +55,23 @@ jobs:
|
||||
NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
PUBLISH_PRERELEASE: ${{ github.event.inputs.prerelease }}
|
||||
- name: 'merge into main branch'
|
||||
if: github.event.inputs.prerelease == '' # unless it's a prerelease
|
||||
- name: 'Create PR to merge into ref branch'
|
||||
run: |
|
||||
git checkout main && \
|
||||
git merge ${{ github.ref }} && \
|
||||
git push
|
||||
gh pr create \
|
||||
-B ${{ github.ref_name }} \
|
||||
-H $PublishBranch \
|
||||
--title "Publish: CHANGELOG and Package Version Updates into ${{ github.ref_name }}" \
|
||||
--body "Syncing CHANGELOG and package version updates from publish action ${{github.run_id}}-${{github.run_number}} into ${{ github.ref_name}} branch" \
|
||||
--reviewer ${{ github.actor }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
- name: 'Create PR to merge ref branch into main'
|
||||
run: |
|
||||
gh pr create \
|
||||
-B main \
|
||||
-H ${{ github.ref_name }} \
|
||||
--title "Publish: Sync ${{ github.ref_name }} into main " \
|
||||
--body "Syncing ${{ github.ref_name }} back into main after publish action. NOTE: this PR should be merged after CHANGELOG and package version updates have been merged into ${{ github.ref_name }}" \
|
||||
--reviewer ${{ github.actor }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
40
.github/workflows/stale.yml
vendored
Normal file
40
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: "Close stale issues and PRs"
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 8 * * 1-5" # This is in UTC.
|
||||
# Do a dry-run (debug-only: true) whenever this workflow itself is changed.
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/stale.yml
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v7
|
||||
with:
|
||||
ascending: true # Spend API operations budget on older, more-likely-to-get-closed issues first
|
||||
close-issue-message: "" # Leave no comment when closing
|
||||
close-pr-message: "" # Leave no comment when closing
|
||||
days-before-issue-stale: 30
|
||||
days-before-pr-stale: 30
|
||||
days-before-close: 14
|
||||
debug-only: ${{ github.event_name == 'pull_request' }} # Dry-run when true.
|
||||
exempt-issue-labels: bug,enhancement,feature,question
|
||||
# No actual changes get made in debug-only mode, so we can raise the operations ceiling.
|
||||
operations-per-run: ${{ github.event_name == 'pull_request' && 100 || 30}}
|
||||
stale-issue-label: stale
|
||||
stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
|
||||
stale-pr-label: stale
|
||||
stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
|
||||
# Time immemorial when in debug-only mode (ie. on pull requests).
|
||||
# `STALEBOT_START_DATE` otherwise.
|
||||
# You can use this as a killswitch by setting `STALEBOT_START_DATE` in the far future.
|
||||
start-date: ${{ github.event_name == 'pull_request' && '1970-01-01T00:00:00Z' || secrets.STALEBOT_START_DATE }} # ISO 8601 or RFC 2822
|
132
.gitignore
vendored
132
.gitignore
vendored
@@ -15,9 +15,6 @@ pids
|
||||
*.db
|
||||
*.sqlite
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
@@ -66,7 +63,16 @@ typings/
|
||||
.env
|
||||
|
||||
# built library using in commonjs module syntax
|
||||
lib/
|
||||
contracts/erc20/lib/
|
||||
contracts/test-utils/lib/
|
||||
contracts/treasury/lib/
|
||||
contracts/utils/lib/
|
||||
contracts/zero-ex/lib/
|
||||
packages/contract-addresses/lib/
|
||||
packages/contract-artifacts/lib/
|
||||
packages/contract-wrappers/lib/
|
||||
packages/protocol-utils/lib/
|
||||
|
||||
# UMD bundles that export the global variable
|
||||
_bundles
|
||||
|
||||
@@ -78,105 +84,43 @@ TODO.md
|
||||
# IDE file
|
||||
.vscode
|
||||
.idea
|
||||
*~
|
||||
.\#*
|
||||
\#*\#
|
||||
|
||||
# generated contract artifacts/
|
||||
contracts/broker/generated-artifacts/
|
||||
contracts/broker/test/generated-artifacts/
|
||||
contracts/erc20-bridge-sampler/generated-artifacts/
|
||||
contracts/erc20-bridge-sampler/test/generated-artifacts/
|
||||
contracts/integrations/generated-artifacts/
|
||||
contracts/integrations/test/generated-artifacts/
|
||||
contracts/staking/generated-artifacts/
|
||||
contracts/staking/test/generated-artifacts/
|
||||
contracts/coordinator/generated-artifacts/
|
||||
contracts/coordinator/test/generated-artifacts/
|
||||
contracts/exchange/generated-artifacts/
|
||||
contracts/exchange/test/generated-artifacts/
|
||||
contracts/asset-proxy/generated-artifacts/
|
||||
contracts/asset-proxy/test/generated-artifacts/
|
||||
contracts/multisig/generated-artifacts/
|
||||
contracts/multisig/test/generated-artifacts/
|
||||
contracts/utils/generated-artifacts/
|
||||
contracts/utils/test/generated-artifacts/
|
||||
contracts/exchange-libs/generated-artifacts/
|
||||
contracts/exchange-libs/test/generated-artifacts/
|
||||
contracts/erc20/generated-artifacts/
|
||||
contracts/erc20/test/generated-artifacts/
|
||||
contracts/erc721/generated-artifacts/
|
||||
contracts/erc721/test/generated-artifacts/
|
||||
contracts/erc1155/generated-artifacts/
|
||||
contracts/erc1155/test/generated-artifacts/
|
||||
contracts/extensions/generated-artifacts/
|
||||
contracts/extensions/test/generated-artifacts/
|
||||
contracts/exchange-forwarder/generated-artifacts/
|
||||
contracts/exchange-forwarder/test/generated-artifacts/
|
||||
contracts/dev-utils/generated-artifacts/
|
||||
contracts/dev-utils/test/generated-artifacts/
|
||||
contracts/zero-ex/generated-artifacts/
|
||||
contracts/zero-ex/test/generated-artifacts/
|
||||
contracts/treasury/generated-artifacts/
|
||||
contracts/treasury/test/generated-artifacts/
|
||||
|
||||
# generated truffle contract artifacts/
|
||||
contracts/broker/build/
|
||||
contracts/erc20-bridge-sampler/build/
|
||||
contracts/staking/build/
|
||||
contracts/coordinator/build/
|
||||
contracts/exchange/build/
|
||||
contracts/asset-proxy/build/
|
||||
contracts/multisig/build/
|
||||
contracts/utils/build/
|
||||
contracts/exchange-libs/build/
|
||||
contracts/erc20/build/
|
||||
contracts/erc721/build/
|
||||
contracts/erc1155/build/
|
||||
contracts/extensions/build/
|
||||
contracts/exchange-forwarder/build/
|
||||
contracts/dev-utils/build/
|
||||
generated-artifacts/
|
||||
|
||||
# generated contract wrappers
|
||||
contracts/broker/generated-wrappers/
|
||||
contracts/broker/test/generated-wrappers/
|
||||
packages/python-contract-wrappers/generated/
|
||||
contracts/erc20-bridge-sampler/generated-wrappers/
|
||||
contracts/erc20-bridge-sampler/test/generated-wrappers/
|
||||
contracts/integrations/generated-wrappers/
|
||||
contracts/integrations/test/generated-wrappers/
|
||||
contracts/staking/generated-wrappers/
|
||||
contracts/staking/test/generated-wrappers/
|
||||
contracts/coordinator/generated-wrappers/
|
||||
contracts/coordinator/test/generated-wrappers/
|
||||
contracts/exchange/generated-wrappers/
|
||||
contracts/exchange/test/generated-wrappers/
|
||||
contracts/asset-proxy/generated-wrappers/
|
||||
contracts/asset-proxy/test/generated-wrappers/
|
||||
contracts/multisig/generated-wrappers/
|
||||
contracts/multisig/test/generated-wrappers/
|
||||
contracts/utils/generated-wrappers/
|
||||
contracts/utils/test/generated-wrappers/
|
||||
contracts/exchange-libs/generated-wrappers/
|
||||
contracts/exchange-libs/test/generated-wrappers/
|
||||
contracts/erc20/generated-wrappers/
|
||||
contracts/erc20/test/generated-wrappers/
|
||||
contracts/erc721/generated-wrappers/
|
||||
contracts/erc721/test/generated-wrappers/
|
||||
contracts/erc1155/generated-wrappers/
|
||||
contracts/erc1155/test/generated-wrappers/
|
||||
contracts/extensions/generated-wrappers/
|
||||
contracts/extensions/test/generated-wrappers/
|
||||
contracts/exchange-forwarder/generated-wrappers/
|
||||
contracts/exchange-forwarder/test/generated-wrappers/
|
||||
contracts/dev-utils/generated-wrappers/
|
||||
contracts/dev-utils/test/generated-wrappers/
|
||||
contracts/zero-ex/generated-wrappers/
|
||||
contracts/zero-ex/test/generated-wrappers/
|
||||
contracts/treasury/generated-wrappers/
|
||||
contracts/treasury/test/generated-wrappers/
|
||||
generated-wrappers/
|
||||
|
||||
# forge std-lib
|
||||
contracts/zero-ex/contracts/deps/forge-std
|
||||
|
||||
# foundry artifacts
|
||||
foundry-artifacts/
|
||||
|
||||
# foundry cache
|
||||
cache/
|
||||
foundry-cache/
|
||||
|
||||
#foundry output artifacts
|
||||
out/
|
||||
|
||||
# typechain wrappers
|
||||
contracts/zero-ex/typechain-wrappers/
|
||||
|
||||
# foundry packages
|
||||
contracts/governance/cache
|
||||
contracts/governance/out
|
||||
|
||||
# Doc README copy
|
||||
packages/*/docs/README.md
|
||||
|
||||
.DS_Store
|
||||
*~
|
||||
\#*\#
|
||||
.\#*
|
||||
|
||||
# the snapshot that gets built for migrations sure does have a ton of files
|
||||
packages/migrations/0x_ganache_snapshot*
|
||||
|
17
.gitmodules
vendored
Normal file
17
.gitmodules
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
|
||||
path = contracts/zero-ex/contracts/deps/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "contracts/erc20/lib/forge-std"]
|
||||
path = contracts/erc20/lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "contracts/governance/lib/forge-std"]
|
||||
path = contracts/governance/lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "contracts/governance/lib/openzeppelin-contracts"]
|
||||
path = contracts/governance/lib/openzeppelin-contracts
|
||||
url = https://github.com/openzeppelin/openzeppelin-contracts
|
||||
[submodule "contracts/governance/lib/openzeppelin-contracts-upgradeable"]
|
||||
path = contracts/governance/lib/openzeppelin-contracts-upgradeable
|
||||
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
|
||||
[submodule "lib/openzeppelin-contracts-upgradeable"]
|
||||
branch = v4.8.2
|
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged --no-stash
|
@@ -1,90 +1,10 @@
|
||||
lib
|
||||
deps
|
||||
.nyc_output
|
||||
/contracts/broker/generated-wrappers
|
||||
/contracts/broker/test/generated-wrappers
|
||||
/contracts/broker/generated-artifacts
|
||||
/contracts/broker/test/generated-artifacts
|
||||
/contracts/integrations/generated-wrappers
|
||||
/contracts/integrations/test/generated-wrappers
|
||||
/contracts/integrations/generated-artifacts
|
||||
/contracts/integrations/test/generated-artifacts
|
||||
/contracts/staking/generated-wrappers
|
||||
/contracts/staking/test/generated-wrappers
|
||||
/contracts/staking/generated-artifacts
|
||||
/contracts/staking/test/generated-artifacts
|
||||
/contracts/coordinator/generated-wrappers
|
||||
/contracts/coordinator/test/generated-wrappers
|
||||
/contracts/coordinator/generated-artifacts
|
||||
/contracts/coordinator/test/generated-artifacts
|
||||
/contracts/exchange/generated-wrappers
|
||||
/contracts/exchange/test/generated-wrappers
|
||||
/contracts/exchange/generated-artifacts
|
||||
/contracts/exchange/test/generated-artifacts
|
||||
/contracts/asset-proxy/generated-wrappers
|
||||
/contracts/asset-proxy/test/generated-wrappers
|
||||
/contracts/asset-proxy/generated-artifacts
|
||||
/contracts/asset-proxy/test/generated-artifacts
|
||||
/contracts/multisig/generated-wrappers
|
||||
/contracts/multisig/test/generated-wrappers
|
||||
/contracts/multisig/generated-artifacts
|
||||
/contracts/multisig/test/generated-artifacts
|
||||
/contracts/utils/generated-wrappers
|
||||
/contracts/utils/test/generated-wrappers
|
||||
/contracts/utils/generated-artifacts
|
||||
/contracts/utils/test/generated-artifacts
|
||||
/contracts/exchange-libs/generated-wrappers
|
||||
/contracts/exchange-libs/test/generated-wrappers
|
||||
/contracts/exchange-libs/generated-artifacts
|
||||
/contracts/exchange-libs/test/generated-artifacts
|
||||
/contracts/erc20/generated-wrappers
|
||||
/contracts/erc20/test/generated-wrappers
|
||||
/contracts/erc20/generated-artifacts
|
||||
/contracts/erc20/test/generated-artifacts
|
||||
/contracts/erc721/generated-wrappers
|
||||
/contracts/erc721/test/generated-wrappers
|
||||
/contracts/erc721/generated-artifacts
|
||||
/contracts/erc721/test/generated-artifacts
|
||||
/contracts/erc1155/generated-wrappers
|
||||
/contracts/erc1155/test/generated-wrappers
|
||||
/contracts/erc1155/generated-artifacts
|
||||
/contracts/erc1155/test/generated-artifacts
|
||||
/contracts/extensions/generated-wrappers
|
||||
/contracts/extensions/test/generated-wrappers
|
||||
/contracts/extensions/generated-artifacts
|
||||
/contracts/extensions/test/generated-artifacts
|
||||
/contracts/exchange-forwarder/generated-wrappers
|
||||
/contracts/exchange-forwarder/test/generated-wrappers
|
||||
/contracts/exchange-forwarder/generated-artifacts
|
||||
/contracts/exchange-forwarder/test/generated-artifacts
|
||||
/contracts/dev-utils/generated-wrappers
|
||||
/contracts/dev-utils/test/generated-wrappers
|
||||
/contracts/dev-utils/generated-artifacts
|
||||
/contracts/dev-utils/test/generated-artifacts
|
||||
/contracts/zero-ex/generated-wrappers
|
||||
/contracts/zero-ex/test/generated-wrappers
|
||||
/contracts/zero-ex/generated-artifacts
|
||||
/contracts/zero-ex/test/generated-artifacts
|
||||
/contracts/treasury/generated-wrappers
|
||||
/contracts/treasury/test/generated-wrappers
|
||||
/contracts/treasury/generated-artifacts
|
||||
/contracts/treasury/test/generated-artifacts
|
||||
/contracts/staking/build/
|
||||
/contracts/coordinator/build/
|
||||
/contracts/exchange/build/
|
||||
/contracts/asset-proxy/build/
|
||||
/contracts/multisig/build/
|
||||
/contracts/utils/build/
|
||||
/contracts/exchange-libs/build/
|
||||
/contracts/erc20/build/
|
||||
/contracts/erc721/build/
|
||||
/contracts/erc1155/build/
|
||||
/contracts/extensions/build/
|
||||
/contracts/exchange-forwarder/build/
|
||||
/packages/asset-swapper/generated-artifacts
|
||||
/packages/asset-swapper/generated-wrappers
|
||||
/packages/asset-swapper/test/generated-artifacts
|
||||
/packages/asset-swapper/test/generated-wrappers
|
||||
generated-artifacts/
|
||||
generated-wrappers/
|
||||
foundry-artifacts/
|
||||
out/
|
||||
cache/
|
||||
package.json
|
||||
packages/*/docs
|
||||
docs/
|
||||
*.sol
|
||||
packages
|
||||
|
14
.prettierrc
14
.prettierrc
@@ -4,5 +4,17 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "avoid"
|
||||
"arrowParens": "avoid",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.sol",
|
||||
"options": {
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
17
.solhint.json
Normal file
17
.solhint.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "solhint:recommended",
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"avoid-low-level-calls": "off",
|
||||
"avoid-tx-origin": "warn",
|
||||
"code-complexity": "off",
|
||||
"const-name-snakecase": "error",
|
||||
"function-max-lines": ["error", 350],
|
||||
"max-line-length": ["error", 120],
|
||||
"no-inline-assembly": "off",
|
||||
"quotes": ["error", "double"],
|
||||
"no-empty-blocks": "off",
|
||||
"compiler-version": "off"
|
||||
}
|
||||
}
|
9
.solhintignore
Normal file
9
.solhintignore
Normal file
@@ -0,0 +1,9 @@
|
||||
contracts/erc20/src/ZRXToken.sol
|
||||
node_modules/
|
||||
lib
|
||||
deps
|
||||
generated-artifacts/
|
||||
generated-wrappers/
|
||||
foundry-artifacts/
|
||||
out/
|
||||
cache/
|
18
CODEOWNERS
18
CODEOWNERS
@@ -1,18 +0,0 @@
|
||||
# See https://help.github.com/articles/about-codeowners/
|
||||
# for more info about CODEOWNERS file
|
||||
|
||||
# It uses the same pattern rule for gitignore file
|
||||
# https://git-scm.com/docs/gitignore#_pattern_format
|
||||
|
||||
# Website
|
||||
packages/asset-swapper/ @BMillman19 @fragosti @dave4506
|
||||
packages/instant/ @BMillman19 @fragosti @dave4506
|
||||
|
||||
# Dev tools & setup
|
||||
.circleci/ @dorothy-zbornak
|
||||
packages/contract-addresses/ @abandeali1
|
||||
packages/contract-artifacts/ @abandeali1
|
||||
packages/order-utils/ @dorothy-zbornak
|
||||
|
||||
# Protocol/smart contracts
|
||||
contracts/ @abandeali1 @hysz @dorothy-zbornak @mzhu25
|
19
README.md
19
README.md
@@ -8,8 +8,7 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
|
||||
|
||||
[website-url]: https://0x.org
|
||||
|
||||
[](https://circleci.com/gh/0xProject/protocool)
|
||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
|
||||
[](https://coveralls.io/github/0xProject/protocol?branch=development)
|
||||
[](https://discordapp.com/invite/d3FTX3M)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
@@ -34,11 +33,9 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| [`@0x/asset-swapper`](/packages/asset-swapper) | [](https://www.npmjs.com/package/@0x/asset-swapper) | Package used to find and create aggregated swaps |
|
||||
| [`@0x/protocol-utils`](/packages/protocol-utils) | [](https://www.npmjs.com/package/@0x/protocol-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
|
||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
|
||||
|
||||
## Usage
|
||||
@@ -56,7 +53,7 @@ You can include those by prepending the `@0x/typescript-typings` package to your
|
||||
|
||||
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.
|
||||
|
||||
#### Read our [contribution guidelines](./CONTRIBUTING.md).
|
||||
#### Read our [contribution guidelines](.github/CONTRIBUTING.md).
|
||||
|
||||
### Install dependencies
|
||||
|
||||
@@ -83,7 +80,7 @@ yarn build
|
||||
To build a specific package:
|
||||
|
||||
```bash
|
||||
PKG=@0x/asset-swapper yarn build
|
||||
PKG=@0x/protocol-utils yarn build
|
||||
```
|
||||
|
||||
To build all contracts packages:
|
||||
@@ -106,7 +103,7 @@ To watch a specific package and all it's dependent packages:
|
||||
PKG=[NPM_PACKAGE_NAME] yarn watch
|
||||
|
||||
e.g
|
||||
PKG=@0x/asset-swapper yarn watch
|
||||
PKG=@0x/protocol-utils yarn watch
|
||||
```
|
||||
|
||||
### Clean
|
||||
@@ -120,7 +117,7 @@ yarn clean
|
||||
Clean a specific package
|
||||
|
||||
```bash
|
||||
PKG=@0x/asset-swapper yarn clean
|
||||
PKG=@0x/protocol-utils yarn clean
|
||||
```
|
||||
|
||||
### Rebuild
|
||||
@@ -134,7 +131,7 @@ yarn rebuild
|
||||
To re-build (clean & build) a specific package & it's deps:
|
||||
|
||||
```bash
|
||||
PKG=@0x/asset-swapper yarn rebuild
|
||||
PKG=@0x/protocol-utils yarn rebuild
|
||||
```
|
||||
|
||||
### Lint
|
||||
@@ -148,7 +145,7 @@ yarn lint
|
||||
Lint a specific package:
|
||||
|
||||
```bash
|
||||
PKG=@0x/asset-swapper yarn lint
|
||||
PKG=@0x/protocol-utils yarn lint
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
@@ -162,7 +159,7 @@ yarn test
|
||||
Run a specific package's test:
|
||||
|
||||
```bash
|
||||
PKG=@0x/asset-swapper yarn test
|
||||
PKG=@0x/protocol-utils yarn test
|
||||
```
|
||||
|
||||
Run all contracts packages tests:
|
||||
|
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"extends": "default",
|
||||
"rules": {
|
||||
"avoid-low-level-calls": false,
|
||||
"avoid-tx-origin": "warn",
|
||||
"bracket-align": false,
|
||||
"code-complexity": false,
|
||||
"compiler-fixed": false,
|
||||
"const-name-snakecase": "error",
|
||||
"expression-indent": "error",
|
||||
"function-max-lines": false,
|
||||
"func-order": "error",
|
||||
"indent": ["error", 4],
|
||||
"max-line-length": ["warn", 160],
|
||||
"no-inline-assembly": false,
|
||||
"quotes": ["error", "double"],
|
||||
"separate-by-one-line-in-contract": "error",
|
||||
"space-after-comma": "error",
|
||||
"statement-indent": "error",
|
||||
"no-empty-blocks": false
|
||||
}
|
||||
}
|
@@ -1 +0,0 @@
|
||||
contracts/src/ZRXToken.sol
|
@@ -1,4 +1,436 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1693346928,
|
||||
"version": "4.0.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1692368658,
|
||||
"version": "4.0.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1691617396,
|
||||
"version": "4.0.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1689974915,
|
||||
"version": "4.0.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1689791426,
|
||||
"version": "4.0.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1683749017,
|
||||
"version": "4.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1682976338,
|
||||
"version": "4.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1681969282,
|
||||
"version": "4.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1681756154
|
||||
},
|
||||
{
|
||||
"timestamp": 1681697326,
|
||||
"version": "4.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1681157139,
|
||||
"version": "4.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1678410794,
|
||||
"version": "4.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Migrated package to foundry"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "3.3.57",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675105183,
|
||||
"version": "3.3.56",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1674517560,
|
||||
"version": "3.3.55",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1670879498,
|
||||
"version": "3.3.54",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1669235113,
|
||||
"version": "3.3.53",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1668477029,
|
||||
"version": "3.3.52",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1667607537,
|
||||
"version": "3.3.51",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1667427402,
|
||||
"version": "3.3.50",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1666645023,
|
||||
"version": "3.3.49",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1666381417,
|
||||
"version": "3.3.48",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1665670315,
|
||||
"version": "3.3.47",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1665531940,
|
||||
"version": "3.3.46",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.3.45",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Migrate from TSLint to ESLint and fix linting errors",
|
||||
"pr": 589
|
||||
}
|
||||
],
|
||||
"timestamp": 1665013355
|
||||
},
|
||||
{
|
||||
"timestamp": 1663786955,
|
||||
"version": "3.3.44",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662998180,
|
||||
"version": "3.3.43",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662559804,
|
||||
"version": "3.3.42",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662147076,
|
||||
"version": "3.3.41",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662046042,
|
||||
"version": "3.3.40",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661462289,
|
||||
"version": "3.3.39",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661459661,
|
||||
"version": "3.3.38",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661145612,
|
||||
"version": "3.3.37",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1660093941,
|
||||
"version": "3.3.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1660073235,
|
||||
"version": "3.3.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1659750766,
|
||||
"version": "3.3.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1658950329,
|
||||
"version": "3.3.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1655244958,
|
||||
"version": "3.3.32",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1654284040,
|
||||
"version": "3.3.31",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1652919697,
|
||||
"version": "3.3.30",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1650611093,
|
||||
"version": "3.3.29",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1648739346,
|
||||
"version": "3.3.28",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1646225739,
|
||||
"version": "3.3.27",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1645569128,
|
||||
"version": "3.3.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1640364306,
|
||||
"version": "3.3.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1638390144,
|
||||
"version": "3.3.24",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1637102971,
|
||||
"version": "3.3.23",
|
||||
|
@@ -5,6 +5,198 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.13 - _August 29, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.12 - _August 18, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.11 - _August 9, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.10 - _July 21, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.9 - _July 19, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.8 - _May 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.7 - _May 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.6 - _April 20, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.5 - _April 17, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.4 - _April 17, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.3 - _April 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.2 - _March 10, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.1 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.0 - _Invalid date_
|
||||
|
||||
* Migrated package to foundry
|
||||
|
||||
## v3.3.57 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.56 - _January 30, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.55 - _January 23, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.54 - _December 12, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.53 - _November 23, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.52 - _November 15, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.51 - _November 5, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.50 - _November 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.49 - _October 24, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.48 - _October 21, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.47 - _October 13, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.46 - _October 11, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.45 - _October 5, 2022_
|
||||
|
||||
* Migrate from TSLint to ESLint and fix linting errors (#589)
|
||||
|
||||
## v3.3.44 - _September 21, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.43 - _September 12, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.42 - _September 7, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.41 - _September 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.40 - _September 1, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.39 - _August 25, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.38 - _August 25, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.37 - _August 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.36 - _August 10, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.35 - _August 9, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.34 - _August 6, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.33 - _July 27, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.32 - _June 14, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.31 - _June 3, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.30 - _May 19, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.29 - _April 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.28 - _March 31, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.27 - _March 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.26 - _February 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.25 - _December 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.24 - _December 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.23 - _November 16, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -20,7 +20,7 @@ We strongly recommend that the community help us make improvements and determine
|
||||
|
||||
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.
|
||||
Please read our [contribution guidelines](../../.github/CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
@@ -67,7 +67,3 @@ yarn lint
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
#### Testing options
|
||||
|
||||
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
||||
|
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"artifactsDir": "./test/generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"shouldSaveStandardInput": true,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "istanbul",
|
||||
"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",
|
||||
"devdoc"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
import "./interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
contract ERC20Token is
|
||||
IERC20Token
|
||||
{
|
||||
mapping (address => uint256) internal balances;
|
||||
mapping (address => mapping (address => uint256)) internal allowed;
|
||||
|
||||
uint256 internal _totalSupply;
|
||||
|
||||
/// @dev send `value` token to `to` from `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return True if transfer was successful
|
||||
function transfer(address _to, uint256 _value)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
require(
|
||||
balances[msg.sender] >= _value,
|
||||
"ERC20_INSUFFICIENT_BALANCE"
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
"UINT256_OVERFLOW"
|
||||
);
|
||||
|
||||
balances[msg.sender] -= _value;
|
||||
balances[_to] += _value;
|
||||
|
||||
emit Transfer(
|
||||
msg.sender,
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// @return True if transfer was successful
|
||||
function transferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
require(
|
||||
balances[_from] >= _value,
|
||||
"ERC20_INSUFFICIENT_BALANCE"
|
||||
);
|
||||
require(
|
||||
allowed[_from][msg.sender] >= _value,
|
||||
"ERC20_INSUFFICIENT_ALLOWANCE"
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
"UINT256_OVERFLOW"
|
||||
);
|
||||
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
|
||||
emit Transfer(
|
||||
_from,
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev `msg.sender` approves `_spender` to spend `_value` tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @param _value The amount of wei to be approved for transfer
|
||||
/// @return Always true if the call has enough gas to complete execution
|
||||
function approve(address _spender, uint256 _value)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
allowed[msg.sender][_spender] = _value;
|
||||
emit Approval(
|
||||
msg.sender,
|
||||
_spender,
|
||||
_value
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Query total supply of token
|
||||
/// @return Total supply of token
|
||||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return _totalSupply;
|
||||
}
|
||||
|
||||
/// @dev Query the balance of owner
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return Balance of owner
|
||||
function balanceOf(address _owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
/// @param _owner The address of the account owning tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address _owner, address _spender)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
}
|
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "../src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
library LibERC20Token {
|
||||
bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()`.
|
||||
/// Reverts if `false` is returned or if the return
|
||||
/// data length is nonzero and not 32 bytes.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param allowance The allowance to set.
|
||||
function approve(
|
||||
address token,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
IERC20Token(0).approve.selector,
|
||||
spender,
|
||||
allowance
|
||||
);
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
|
||||
/// maximum if the current approval is not already >= an amount.
|
||||
/// Reverts if `false` is returned or if the return
|
||||
/// data length is nonzero and not 32 bytes.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param amount The minimum allowance needed.
|
||||
function approveIfBelow(
|
||||
address token,
|
||||
address spender,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (IERC20Token(token).allowance(address(this), spender) < amount) {
|
||||
approve(token, spender, uint256(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transfer()`.
|
||||
/// Reverts if `false` is returned or if the return
|
||||
/// data length is nonzero and not 32 bytes.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function transfer(
|
||||
address token,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
IERC20Token(0).transfer.selector,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transferFrom()`.
|
||||
/// Reverts if `false` is returned or if the return
|
||||
/// data length is nonzero and not 32 bytes.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param from The owner of the tokens.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function transferFrom(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
IERC20Token(0).transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Retrieves the number of decimals for a token.
|
||||
/// Returns `18` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @return tokenDecimals The number of decimals places for the token.
|
||||
function decimals(address token)
|
||||
internal
|
||||
view
|
||||
returns (uint8 tokenDecimals)
|
||||
{
|
||||
tokenDecimals = 18;
|
||||
(bool didSucceed, bytes memory resultData) = token.staticcall(DECIMALS_CALL_DATA);
|
||||
if (didSucceed && resultData.length == 32) {
|
||||
tokenDecimals = uint8(LibBytes.readUint256(resultData, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrieves the allowance for a token, owner, and spender.
|
||||
/// Returns `0` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @param spender The address the spender.
|
||||
/// @return allowance The allowance for a token, owner, and spender.
|
||||
function allowance(address token, address owner, address spender)
|
||||
internal
|
||||
view
|
||||
returns (uint256 allowance_)
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = token.staticcall(
|
||||
abi.encodeWithSelector(
|
||||
IERC20Token(0).allowance.selector,
|
||||
owner,
|
||||
spender
|
||||
)
|
||||
);
|
||||
if (didSucceed && resultData.length == 32) {
|
||||
allowance_ = LibBytes.readUint256(resultData, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrieves the balance for a token owner.
|
||||
/// Returns `0` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @return balance The token balance of an owner.
|
||||
function balanceOf(address token, address owner)
|
||||
internal
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = token.staticcall(
|
||||
abi.encodeWithSelector(
|
||||
IERC20Token(0).balanceOf.selector,
|
||||
owner
|
||||
)
|
||||
);
|
||||
if (didSucceed && resultData.length == 32) {
|
||||
balance = LibBytes.readUint256(resultData, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Executes a call on address `target` with calldata `callData`
|
||||
/// and asserts that either nothing was returned or a single boolean
|
||||
/// was returned equal to `true`.
|
||||
/// @param target The call target.
|
||||
/// @param callData The abi-encoded call data.
|
||||
function _callWithOptionalBooleanResult(
|
||||
address target,
|
||||
bytes memory callData
|
||||
)
|
||||
private
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = target.call(callData);
|
||||
if (didSucceed) {
|
||||
if (resultData.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (resultData.length == 32) {
|
||||
uint256 result = LibBytes.readUint256(resultData, 0);
|
||||
if (result == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
LibRichErrors.rrevert(resultData);
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./UnlimitedAllowanceERC20Token.sol";
|
||||
|
||||
|
||||
contract MintableERC20Token is
|
||||
UnlimitedAllowanceERC20Token
|
||||
{
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
/// @dev Mints new tokens
|
||||
/// @param _to Address of the beneficiary that will own the minted token
|
||||
/// @param _value Amount of tokens to mint
|
||||
function _mint(address _to, uint256 _value)
|
||||
internal
|
||||
{
|
||||
balances[_to] = _value.safeAdd(balances[_to]);
|
||||
_totalSupply = _totalSupply.safeAdd(_value);
|
||||
|
||||
emit Transfer(
|
||||
address(0),
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Mints new tokens
|
||||
/// @param _owner Owner of tokens that will be burned
|
||||
/// @param _value Amount of tokens to burn
|
||||
function _burn(address _owner, uint256 _value)
|
||||
internal
|
||||
{
|
||||
balances[_owner] = balances[_owner].safeSub(_value);
|
||||
_totalSupply = _totalSupply.safeSub(_value);
|
||||
|
||||
emit Transfer(
|
||||
_owner,
|
||||
address(0),
|
||||
_value
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
import "./ERC20Token.sol";
|
||||
|
||||
|
||||
contract UnlimitedAllowanceERC20Token is
|
||||
ERC20Token
|
||||
{
|
||||
uint256 constant internal MAX_UINT = 2**256 - 1;
|
||||
|
||||
/// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717
|
||||
/// @param _from Address to transfer from.
|
||||
/// @param _to Address to transfer to.
|
||||
/// @param _value Amount to transfer.
|
||||
/// @return Success of transfer.
|
||||
function transferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
uint256 allowance = allowed[_from][msg.sender];
|
||||
require(
|
||||
balances[_from] >= _value,
|
||||
"ERC20_INSUFFICIENT_BALANCE"
|
||||
);
|
||||
require(
|
||||
allowance >= _value,
|
||||
"ERC20_INSUFFICIENT_ALLOWANCE"
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
"UINT256_OVERFLOW"
|
||||
);
|
||||
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
if (allowance < MAX_UINT) {
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
}
|
||||
|
||||
emit Transfer(
|
||||
_from,
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
|
||||
contract IERC20Token {
|
||||
|
||||
// solhint-disable no-simple-event-func-name
|
||||
event Transfer(
|
||||
address indexed _from,
|
||||
address indexed _to,
|
||||
uint256 _value
|
||||
);
|
||||
|
||||
event Approval(
|
||||
address indexed _owner,
|
||||
address indexed _spender,
|
||||
uint256 _value
|
||||
);
|
||||
|
||||
/// @dev send `value` token to `to` from `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return True if transfer was successful
|
||||
function transfer(address _to, uint256 _value)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @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
|
||||
/// @return True if transfer was successful
|
||||
function transferFrom(
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _value
|
||||
)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @dev `msg.sender` approves `_spender` to spend `_value` tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @param _value The amount of wei to be approved for transfer
|
||||
/// @return Always true if the call has enough gas to complete execution
|
||||
function approve(address _spender, uint256 _value)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @dev Query total supply of token
|
||||
/// @return Total supply of token
|
||||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return Balance of owner
|
||||
function balanceOf(address _owner)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/// @param _owner The address of the account owning tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address _owner, address _spender)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
import "./IERC20Token.sol";
|
||||
|
||||
|
||||
contract IEtherToken is
|
||||
IERC20Token
|
||||
{
|
||||
function deposit()
|
||||
public
|
||||
payable;
|
||||
|
||||
function withdraw(uint256 amount)
|
||||
public;
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "../src/MintableERC20Token.sol";
|
||||
|
||||
|
||||
contract DummyERC20Token is
|
||||
Ownable,
|
||||
MintableERC20Token
|
||||
{
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint256 public decimals;
|
||||
uint256 public constant MAX_MINT_AMOUNT = 10000000000000000000000;
|
||||
|
||||
constructor (
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint256 _decimals,
|
||||
uint256 _totalSupply
|
||||
)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
_totalSupply = _totalSupply;
|
||||
balances[msg.sender] = _totalSupply;
|
||||
}
|
||||
|
||||
/// @dev Sets the balance of target address
|
||||
/// @param _target Address or which balance will be updated
|
||||
/// @param _value New balance of target address
|
||||
function setBalance(address _target, uint256 _value)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
uint256 currBalance = balances[_target];
|
||||
if (_value < currBalance) {
|
||||
_totalSupply = _totalSupply.safeSub(currBalance.safeSub(_value));
|
||||
} else {
|
||||
_totalSupply = _totalSupply.safeAdd(_value.safeSub(currBalance));
|
||||
}
|
||||
balances[_target] = _value;
|
||||
}
|
||||
|
||||
/// @dev Mints new tokens for sender
|
||||
/// @param _value Amount of tokens to mint
|
||||
function mint(uint256 _value)
|
||||
external
|
||||
{
|
||||
require(
|
||||
_value <= MAX_MINT_AMOUNT,
|
||||
"VALUE_TOO_LARGE"
|
||||
);
|
||||
|
||||
_mint(msg.sender, _value);
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
import "./DummyERC20Token.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract DummyMultipleReturnERC20Token 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)
|
||||
{
|
||||
emit Transfer(
|
||||
_from,
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
|
||||
// HACK: This contract will not compile if we remove `returns (bool)`, so we manually return 64 bytes (equiavalent to true, true)
|
||||
assembly {
|
||||
mstore(0, 1)
|
||||
mstore(32, 1)
|
||||
return(0, 64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
import "./DummyERC20Token.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract DummyNoReturnERC20Token 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 `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
function transfer(address _to, uint256 _value)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
require(
|
||||
balances[msg.sender] >= _value,
|
||||
"ERC20_INSUFFICIENT_BALANCE"
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
"UINT256_OVERFLOW"
|
||||
);
|
||||
|
||||
balances[msg.sender] -= _value;
|
||||
balances[_to] += _value;
|
||||
|
||||
emit Transfer(
|
||||
msg.sender,
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
|
||||
// HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
|
||||
assembly {
|
||||
return(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// @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(
|
||||
balances[_from] >= _value,
|
||||
"ERC20_INSUFFICIENT_BALANCE"
|
||||
);
|
||||
require(
|
||||
allowed[_from][msg.sender] >= _value,
|
||||
"ERC20_INSUFFICIENT_ALLOWANCE"
|
||||
);
|
||||
require(
|
||||
balances[_to] + _value >= balances[_to],
|
||||
"UINT256_OVERFLOW"
|
||||
);
|
||||
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
|
||||
emit Transfer(
|
||||
_from,
|
||||
_to,
|
||||
_value
|
||||
);
|
||||
|
||||
// HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
|
||||
assembly {
|
||||
return(0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
import "../src/LibERC20Token.sol";
|
||||
import "./TestLibERC20TokenTarget.sol";
|
||||
|
||||
|
||||
contract TestLibERC20Token {
|
||||
|
||||
TestLibERC20TokenTarget public target;
|
||||
|
||||
constructor() public {
|
||||
target = new TestLibERC20TokenTarget();
|
||||
}
|
||||
|
||||
function testApprove(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
LibERC20Token.approve(address(target), spender, allowance);
|
||||
}
|
||||
|
||||
function testTransfer(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
LibERC20Token.transfer(address(target), to, amount);
|
||||
}
|
||||
|
||||
function testTransferFrom(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
LibERC20Token.transferFrom(address(target), from, to, amount);
|
||||
}
|
||||
|
||||
function testDecimals(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData
|
||||
)
|
||||
external
|
||||
returns (uint8)
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
return LibERC20Token.decimals(address(target));
|
||||
}
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
|
||||
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.9;
|
||||
|
||||
|
||||
contract TestLibERC20TokenTarget {
|
||||
|
||||
event ApproveCalled(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event TransferCalled(
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TransferFromCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
bool private _shouldRevert;
|
||||
bytes private _revertData;
|
||||
bytes private _returnData;
|
||||
|
||||
function setBehavior(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData
|
||||
)
|
||||
external
|
||||
{
|
||||
_shouldRevert = shouldRevert;
|
||||
_revertData = revertData;
|
||||
_returnData = returnData;
|
||||
}
|
||||
|
||||
function approve(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
emit ApproveCalled(spender, allowance);
|
||||
_execute();
|
||||
}
|
||||
|
||||
function transfer(
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
emit TransferCalled(to, amount);
|
||||
_execute();
|
||||
}
|
||||
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
emit TransferFromCalled(from, to, amount);
|
||||
_execute();
|
||||
}
|
||||
|
||||
function decimals()
|
||||
external
|
||||
view
|
||||
returns (uint8)
|
||||
{
|
||||
_execute();
|
||||
}
|
||||
|
||||
function _execute() private view {
|
||||
if (_shouldRevert) {
|
||||
bytes memory revertData = _revertData;
|
||||
assembly { revert(add(revertData, 0x20), mload(revertData)) }
|
||||
}
|
||||
bytes memory returnData = _returnData;
|
||||
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
import "./DummyERC20Token.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
// solhint-disable no-unused-vars
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
18
contracts/erc20/foundry.toml
Normal file
18
contracts/erc20/foundry.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[profile.default]
|
||||
src = 'src'
|
||||
out = 'out'
|
||||
libs = [
|
||||
'lib',
|
||||
'node_modules',
|
||||
]
|
||||
remappings = [
|
||||
'@0x/contracts-utils/=../utils/'
|
||||
]
|
||||
allow_paths = [
|
||||
'../utils/'
|
||||
]
|
||||
|
||||
fs_permissions = [{ access = "read", path = "./out/ZRXToken.sol" }]
|
||||
|
||||
optimizer_runs = 1_000_000
|
||||
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
|
1
contracts/erc20/lib/forge-std
Submodule
1
contracts/erc20/lib/forge-std
Submodule
Submodule contracts/erc20/lib/forge-std added at fc560fa34f
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.3.23",
|
||||
"version": "4.0.13",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -10,37 +10,10 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||
"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 test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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 generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"test:ci": "forge test",
|
||||
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "DummyERC20Token,ERC20Token,WETH9,ZRXToken,DummyNoReturnERC20Token,DummyMultipleReturnERC20Token",
|
||||
"abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IERC20TokenV06|IEtherToken|IEtherTokenV06|LibERC20Token|LibERC20TokenV06|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
@@ -49,41 +22,11 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"homepage": "https://github.com/0xProject/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.2",
|
||||
"@0x/contracts-gen": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.14",
|
||||
"@0x/contracts-utils": "^4.8.4",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/contracts-utils": "^4.8.51",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"ethers": "~4.0.4"
|
||||
"typedoc": "~0.16.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
Copyright 2023 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -17,80 +17,47 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma solidity >=0.6.5 <0.9;
|
||||
|
||||
interface IERC20Token {
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
|
||||
interface IERC20TokenV06 {
|
||||
|
||||
// solhint-disable no-simple-event-func-name
|
||||
event Transfer(
|
||||
address indexed from,
|
||||
address indexed to,
|
||||
uint256 value
|
||||
);
|
||||
|
||||
event Approval(
|
||||
address indexed owner,
|
||||
address indexed spender,
|
||||
uint256 value
|
||||
);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
|
||||
/// @dev send `value` token to `to` from `msg.sender`
|
||||
/// @param to The address of the recipient
|
||||
/// @param value The amount of token to be transferred
|
||||
/// @return True if transfer was successful
|
||||
function transfer(address to, uint256 value)
|
||||
external
|
||||
returns (bool);
|
||||
function transfer(address to, uint256 value) external returns (bool);
|
||||
|
||||
/// @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
|
||||
/// @return True if transfer was successful
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value
|
||||
)
|
||||
external
|
||||
returns (bool);
|
||||
function transferFrom(address from, address to, uint256 value) external returns (bool);
|
||||
|
||||
/// @dev `msg.sender` approves `spender` to spend `value` tokens
|
||||
/// @param spender The address of the account able to transfer the tokens
|
||||
/// @param value The amount of wei to be approved for transfer
|
||||
/// @return Always true if the call has enough gas to complete execution
|
||||
function approve(address spender, uint256 value)
|
||||
external
|
||||
returns (bool);
|
||||
function approve(address spender, uint256 value) external returns (bool);
|
||||
|
||||
/// @dev Query total supply of token
|
||||
/// @return Total supply of token
|
||||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
function totalSupply() external view returns (uint256);
|
||||
|
||||
/// @dev Get the balance of `owner`.
|
||||
/// @param owner The address from which the balance will be retrieved
|
||||
/// @return Balance of owner
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
function balanceOf(address owner) external view returns (uint256);
|
||||
|
||||
/// @dev Get the allowance for `spender` to spend from `owner`.
|
||||
/// @param owner The address of the account owning tokens
|
||||
/// @param spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address owner, address spender)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
function allowance(address owner, address spender) external view returns (uint256);
|
||||
|
||||
/// @dev Get the number of decimals this token has.
|
||||
function decimals()
|
||||
external
|
||||
view
|
||||
returns (uint8);
|
||||
function decimals() external view returns (uint8);
|
||||
}
|
@@ -19,12 +19,9 @@
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "./IERC20TokenV06.sol";
|
||||
import "./IERC20Token.sol";
|
||||
|
||||
|
||||
interface IEtherTokenV06 is
|
||||
IERC20TokenV06
|
||||
{
|
||||
interface IEtherToken is IERC20Token {
|
||||
/// @dev Wrap ether.
|
||||
function deposit() external payable;
|
||||
|
@@ -13,58 +13,55 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// solhint-disable
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract WETH9 {
|
||||
string public name = "Wrapped Ether";
|
||||
string public symbol = "WETH";
|
||||
uint8 public decimals = 18;
|
||||
string public name = "Wrapped Ether";
|
||||
string public symbol = "WETH";
|
||||
uint8 public decimals = 18;
|
||||
|
||||
event Approval(address indexed _owner, address indexed _spender, uint _value);
|
||||
event Transfer(address indexed _from, address indexed _to, uint _value);
|
||||
event Deposit(address indexed _owner, uint _value);
|
||||
event Withdrawal(address indexed _owner, uint _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Deposit(address indexed _owner, uint256 _value);
|
||||
event Withdrawal(address indexed _owner, uint256 _value);
|
||||
|
||||
mapping (address => uint) public balanceOf;
|
||||
mapping (address => mapping (address => uint)) public allowance;
|
||||
mapping(address => uint256) public balanceOf;
|
||||
mapping(address => mapping(address => uint256)) public allowance;
|
||||
|
||||
function() external payable {
|
||||
deposit();
|
||||
}
|
||||
|
||||
function deposit() public payable {
|
||||
balanceOf[msg.sender] += msg.value;
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
}
|
||||
function withdraw(uint wad) public {
|
||||
|
||||
function withdraw(uint256 wad) public {
|
||||
require(balanceOf[msg.sender] >= wad);
|
||||
balanceOf[msg.sender] -= wad;
|
||||
msg.sender.transfer(wad);
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
}
|
||||
|
||||
function totalSupply() public view returns (uint) {
|
||||
function totalSupply() public view returns (uint256) {
|
||||
return address(this).balance;
|
||||
}
|
||||
|
||||
function approve(address guy, uint wad) public returns (bool) {
|
||||
function approve(address guy, uint256 wad) public returns (bool) {
|
||||
allowance[msg.sender][guy] = wad;
|
||||
emit Approval(msg.sender, guy, wad);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transfer(address dst, uint wad) public returns (bool) {
|
||||
function transfer(address dst, uint256 wad) public returns (bool) {
|
||||
return transferFrom(msg.sender, dst, wad);
|
||||
}
|
||||
|
||||
function transferFrom(address src, address dst, uint wad)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
function transferFrom(address src, address dst, uint256 wad) public returns (bool) {
|
||||
require(balanceOf[src] >= wad);
|
||||
|
||||
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
|
||||
if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
|
||||
require(allowance[src][msg.sender] >= wad);
|
||||
allowance[src][msg.sender] -= wad;
|
||||
}
|
||||
@@ -78,7 +75,6 @@ contract WETH9 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
@@ -18,105 +18,99 @@
|
||||
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
|
||||
contract Token {
|
||||
|
||||
/// @return total amount of tokens
|
||||
function totalSupply() constant returns (uint supply) {}
|
||||
function totalSupply() constant returns (uint256 supply) {}
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return The balance
|
||||
function balanceOf(address _owner) constant returns (uint balance) {}
|
||||
function balanceOf(address _owner) constant returns (uint256 balance) {}
|
||||
|
||||
/// @notice send `_value` token to `_to` from `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transfer(address _to, uint _value) returns (bool success) {}
|
||||
function transfer(address _to, uint256 _value) returns (bool success) {}
|
||||
|
||||
/// @notice 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
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transferFrom(address _from, address _to, uint _value) returns (bool success) {}
|
||||
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
|
||||
|
||||
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @param _value The amount of wei to be approved for transfer
|
||||
/// @return Whether the approval was successful or not
|
||||
function approve(address _spender, uint _value) returns (bool success) {}
|
||||
function approve(address _spender, uint256 _value) returns (bool success) {}
|
||||
|
||||
/// @param _owner The address of the account owning tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address _owner, address _spender) constant returns (uint remaining) {}
|
||||
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
|
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint _value);
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
}
|
||||
|
||||
|
||||
contract ERC20Token is Token {
|
||||
|
||||
function transfer(address _to, uint _value) returns (bool) {
|
||||
function transfer(address _to, uint256 _value) returns (bool) {
|
||||
//Default assumes totalSupply can't be over max (2^256 - 1).
|
||||
if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
|
||||
balances[msg.sender] -= _value;
|
||||
balances[_to] += _value;
|
||||
Transfer(msg.sender, _to, _value);
|
||||
return true;
|
||||
} else { return false; }
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint _value) returns (bool) {
|
||||
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
|
||||
function transferFrom(address _from, address _to, uint256 _value) returns (bool) {
|
||||
if (
|
||||
balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]
|
||||
) {
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
allowed[_from][msg.sender] -= _value;
|
||||
Transfer(_from, _to, _value);
|
||||
return true;
|
||||
} else { return false; }
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function balanceOf(address _owner) constant returns (uint) {
|
||||
function balanceOf(address _owner) constant returns (uint256) {
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
function approve(address _spender, uint _value) returns (bool) {
|
||||
function approve(address _spender, uint256 _value) returns (bool) {
|
||||
allowed[msg.sender][_spender] = _value;
|
||||
Approval(msg.sender, _spender, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address _owner, address _spender) constant returns (uint) {
|
||||
function allowance(address _owner, address _spender) constant returns (uint256) {
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
|
||||
mapping (address => uint) balances;
|
||||
mapping (address => mapping (address => uint)) allowed;
|
||||
uint public totalSupply;
|
||||
mapping(address => uint256) balances;
|
||||
mapping(address => mapping(address => uint256)) allowed;
|
||||
uint256 public totalSupply;
|
||||
}
|
||||
|
||||
|
||||
contract UnlimitedAllowanceToken is ERC20Token {
|
||||
|
||||
uint constant MAX_UINT = 2**256 - 1;
|
||||
uint256 constant MAX_UINT = 2 ** 256 - 1;
|
||||
|
||||
/// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
|
||||
/// @param _from Address to transfer from.
|
||||
/// @param _to Address to transfer to.
|
||||
/// @param _value Amount to transfer.
|
||||
/// @return Success of transfer.
|
||||
function transferFrom(address _from, address _to, uint _value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
uint allowance = allowed[_from][msg.sender];
|
||||
if (balances[_from] >= _value
|
||||
&& allowance >= _value
|
||||
&& balances[_to] + _value >= balances[_to]
|
||||
) {
|
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
|
||||
uint256 allowance = allowed[_from][msg.sender];
|
||||
if (balances[_from] >= _value && allowance >= _value && balances[_to] + _value >= balances[_to]) {
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
if (allowance < MAX_UINT) {
|
||||
@@ -130,21 +124,13 @@ contract UnlimitedAllowanceToken is ERC20Token {
|
||||
}
|
||||
}
|
||||
|
||||
contract ZRXToken is UnlimitedAllowanceToken {
|
||||
uint8 public constant decimals = 18;
|
||||
uint256 public totalSupply = 10 ** 27; // 1 billion tokens, 18 decimal places
|
||||
string public constant name = "0x Protocol Token";
|
||||
string public constant symbol = "ZRX";
|
||||
|
||||
contract ZRXToken is
|
||||
UnlimitedAllowanceToken
|
||||
{
|
||||
|
||||
// solhint-disable const-name-snakecase
|
||||
uint8 constant public decimals = 18;
|
||||
uint256 public totalSupply = 10**27; // 1 billion tokens, 18 decimal places
|
||||
string constant public name = "0x Protocol Token";
|
||||
string constant public symbol = "ZRX";
|
||||
// solhint-enableconst-name-snakecase
|
||||
|
||||
function ZRXToken()
|
||||
public
|
||||
{
|
||||
function ZRXToken() public {
|
||||
balances[msg.sender] = totalSupply;
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as DummyERC20Token from '../generated-artifacts/DummyERC20Token.json';
|
||||
import * as DummyMultipleReturnERC20Token from '../generated-artifacts/DummyMultipleReturnERC20Token.json';
|
||||
import * as DummyNoReturnERC20Token from '../generated-artifacts/DummyNoReturnERC20Token.json';
|
||||
import * as ERC20Token from '../generated-artifacts/ERC20Token.json';
|
||||
import * as WETH9 from '../generated-artifacts/WETH9.json';
|
||||
import * as ZRXToken from '../generated-artifacts/ZRXToken.json';
|
||||
export const artifacts = {
|
||||
DummyERC20Token: DummyERC20Token as ContractArtifact,
|
||||
ERC20Token: ERC20Token as ContractArtifact,
|
||||
WETH9: WETH9 as ContractArtifact,
|
||||
ZRXToken: (ZRXToken as any) as ContractArtifact,
|
||||
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
|
||||
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
|
||||
};
|
@@ -1,47 +0,0 @@
|
||||
export {
|
||||
DummyERC20TokenContract,
|
||||
DummyMultipleReturnERC20TokenContract,
|
||||
DummyNoReturnERC20TokenContract,
|
||||
WETH9Contract,
|
||||
WETH9Events,
|
||||
WETH9DepositEventArgs,
|
||||
WETH9TransferEventArgs,
|
||||
WETH9WithdrawalEventArgs,
|
||||
ZRXTokenContract,
|
||||
DummyERC20TokenTransferEventArgs,
|
||||
ERC20TokenEventArgs,
|
||||
ERC20TokenEvents,
|
||||
ERC20TokenTransferEventArgs,
|
||||
ERC20TokenApprovalEventArgs,
|
||||
ERC20TokenContract,
|
||||
} from './wrappers';
|
||||
export { artifacts } from './artifacts';
|
||||
export {
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
CompilerOpts,
|
||||
StandardContractOutput,
|
||||
CompilerSettings,
|
||||
ContractChainData,
|
||||
ContractAbi,
|
||||
DevdocOutput,
|
||||
EvmOutput,
|
||||
CompilerSettingsMetadata,
|
||||
OptimizerSettings,
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
EvmBytecodeOutput,
|
||||
EvmBytecodeOutputLinkReferences,
|
||||
AbiDefinition,
|
||||
FunctionAbi,
|
||||
EventAbi,
|
||||
RevertErrorAbi,
|
||||
EventParameter,
|
||||
DataItem,
|
||||
MethodAbi,
|
||||
ConstructorAbi,
|
||||
FallbackAbi,
|
||||
ConstructorStateMutability,
|
||||
TupleDataItem,
|
||||
StateMutability,
|
||||
} from 'ethereum-types';
|
@@ -21,90 +21,51 @@ pragma solidity ^0.6.5;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
||||
import "./IERC20TokenV06.sol";
|
||||
|
||||
import "../IERC20Token.sol";
|
||||
|
||||
library LibERC20TokenV06 {
|
||||
bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
|
||||
bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).approve()`.
|
||||
/// @dev Calls `IERC20Token(token).approve()`.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param allowance The allowance to set.
|
||||
function compatApprove(
|
||||
IERC20TokenV06 token,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.approve.selector,
|
||||
spender,
|
||||
allowance
|
||||
);
|
||||
function compatApprove(IERC20Token token, address spender, uint256 allowance) internal {
|
||||
bytes memory callData = abi.encodeWithSelector(token.approve.selector, spender, allowance);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).approve()` and sets the allowance to the
|
||||
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
|
||||
/// maximum if the current approval is not already >= an amount.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param amount The minimum allowance needed.
|
||||
function approveIfBelow(
|
||||
IERC20TokenV06 token,
|
||||
address spender,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
function approveIfBelow(IERC20Token token, address spender, uint256 amount) internal {
|
||||
if (token.allowance(address(this), spender) < amount) {
|
||||
compatApprove(token, spender, uint256(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).transfer()`.
|
||||
/// @dev Calls `IERC20Token(token).transfer()`.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function compatTransfer(
|
||||
IERC20TokenV06 token,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.transfer.selector,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
function compatTransfer(IERC20Token token, address to, uint256 amount) internal {
|
||||
bytes memory callData = abi.encodeWithSelector(token.transfer.selector, to, amount);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).transferFrom()`.
|
||||
/// @dev Calls `IERC20Token(token).transferFrom()`.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param from The owner of the tokens.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function compatTransferFrom(
|
||||
IERC20TokenV06 token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
function compatTransferFrom(IERC20Token token, address from, address to, uint256 amount) internal {
|
||||
bytes memory callData = abi.encodeWithSelector(token.transferFrom.selector, from, to, amount);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
@@ -112,11 +73,7 @@ library LibERC20TokenV06 {
|
||||
/// Returns `18` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @return tokenDecimals The number of decimals places for the token.
|
||||
function compatDecimals(IERC20TokenV06 token)
|
||||
internal
|
||||
view
|
||||
returns (uint8 tokenDecimals)
|
||||
{
|
||||
function compatDecimals(IERC20Token token) internal view returns (uint8 tokenDecimals) {
|
||||
tokenDecimals = 18;
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
@@ -130,17 +87,13 @@ library LibERC20TokenV06 {
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @param spender The address the spender.
|
||||
/// @return allowance_ The allowance for a token, owner, and spender.
|
||||
function compatAllowance(IERC20TokenV06 token, address owner, address spender)
|
||||
internal
|
||||
view
|
||||
returns (uint256 allowance_)
|
||||
{
|
||||
function compatAllowance(
|
||||
IERC20Token token,
|
||||
address owner,
|
||||
address spender
|
||||
) internal view returns (uint256 allowance_) {
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
|
||||
abi.encodeWithSelector(
|
||||
token.allowance.selector,
|
||||
owner,
|
||||
spender
|
||||
)
|
||||
abi.encodeWithSelector(token.allowance.selector, owner, spender)
|
||||
);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
allowance_ = LibBytesV06.readUint256(resultData, 0);
|
||||
@@ -152,16 +105,9 @@ library LibERC20TokenV06 {
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @return balance The token balance of an owner.
|
||||
function compatBalanceOf(IERC20TokenV06 token, address owner)
|
||||
internal
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
function compatBalanceOf(IERC20Token token, address owner) internal view returns (uint256 balance) {
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
|
||||
abi.encodeWithSelector(
|
||||
token.balanceOf.selector,
|
||||
owner
|
||||
)
|
||||
abi.encodeWithSelector(token.balanceOf.selector, owner)
|
||||
);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
balance = LibBytesV06.readUint256(resultData, 0);
|
||||
@@ -173,12 +119,7 @@ library LibERC20TokenV06 {
|
||||
/// was returned equal to `true`.
|
||||
/// @param target The call target.
|
||||
/// @param callData The abi-encoded call data.
|
||||
function _callWithOptionalBooleanResult(
|
||||
address target,
|
||||
bytes memory callData
|
||||
)
|
||||
private
|
||||
{
|
||||
function _callWithOptionalBooleanResult(address target, bytes memory callData) private {
|
||||
(bool didSucceed, bytes memory resultData) = target.call(callData);
|
||||
// Revert if the call reverted.
|
||||
if (!didSucceed) {
|
||||
@@ -188,7 +129,9 @@ library LibERC20TokenV06 {
|
||||
// does not return a boolean. Check that it at least contains code.
|
||||
if (resultData.length == 0) {
|
||||
uint256 size;
|
||||
assembly { size := extcodesize(target) }
|
||||
assembly {
|
||||
size := extcodesize(target)
|
||||
}
|
||||
require(size > 0, "invalid token address, contains no code");
|
||||
return;
|
||||
}
|
755
contracts/erc20/src/v06/WETH9V06.sol
Normal file
755
contracts/erc20/src/v06/WETH9V06.sol
Normal file
@@ -0,0 +1,755 @@
|
||||
// Copyright (C) 2015, 2016, 2017 Dapphub
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// solhint-disable
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
contract WETH9V06 {
|
||||
string public name = "Wrapped Ether";
|
||||
string public symbol = "WETH";
|
||||
uint8 public decimals = 18;
|
||||
|
||||
event Approval(address indexed _owner, address indexed _spender, uint _value);
|
||||
event Transfer(address indexed _from, address indexed _to, uint _value);
|
||||
event Deposit(address indexed _owner, uint _value);
|
||||
event Withdrawal(address indexed _owner, uint _value);
|
||||
|
||||
mapping(address => uint) public balanceOf;
|
||||
mapping(address => mapping(address => uint)) public allowance;
|
||||
|
||||
receive() external payable {
|
||||
deposit();
|
||||
}
|
||||
|
||||
function deposit() public payable {
|
||||
balanceOf[msg.sender] += msg.value;
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function withdraw(uint wad) public {
|
||||
require(balanceOf[msg.sender] >= wad);
|
||||
balanceOf[msg.sender] -= wad;
|
||||
msg.sender.transfer(wad);
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
}
|
||||
|
||||
function totalSupply() public view returns (uint) {
|
||||
return address(this).balance;
|
||||
}
|
||||
|
||||
function approve(address guy, uint wad) public returns (bool) {
|
||||
allowance[msg.sender][guy] = wad;
|
||||
emit Approval(msg.sender, guy, wad);
|
||||
return true;
|
||||
}
|
||||
|
||||
function transfer(address dst, uint wad) public returns (bool) {
|
||||
return transferFrom(msg.sender, dst, wad);
|
||||
}
|
||||
|
||||
function transferFrom(address src, address dst, uint wad) public returns (bool) {
|
||||
require(balanceOf[src] >= wad);
|
||||
|
||||
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
|
||||
require(allowance[src][msg.sender] >= wad);
|
||||
allowance[src][msg.sender] -= wad;
|
||||
}
|
||||
|
||||
balanceOf[src] -= wad;
|
||||
balanceOf[dst] += wad;
|
||||
|
||||
emit Transfer(src, dst, wad);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
*/
|
146
contracts/erc20/src/v08/LibERC20TokenV08.sol
Normal file
146
contracts/erc20/src/v08/LibERC20TokenV08.sol
Normal file
@@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 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.8.0;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v08/errors/LibRichErrorsV08.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v08/LibBytesV08.sol";
|
||||
import "../IERC20Token.sol";
|
||||
|
||||
library LibERC20TokenV08 {
|
||||
bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()`.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param allowance The allowance to set.
|
||||
function compatApprove(IERC20Token token, address spender, uint256 allowance) internal {
|
||||
bytes memory callData = abi.encodeCall(token.approve, (spender, allowance));
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
|
||||
/// maximum if the current approval is not already >= an amount.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param amount The minimum allowance needed.
|
||||
function approveIfBelow(IERC20Token token, address spender, uint256 amount) internal {
|
||||
if (token.allowance(address(this), spender) < amount) {
|
||||
compatApprove(token, spender, type(uint256).max);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transfer()`.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function compatTransfer(IERC20Token token, address to, uint256 amount) internal {
|
||||
bytes memory callData = abi.encodeCall(token.transfer, (to, amount));
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transferFrom()`.
|
||||
/// Reverts if the return data is invalid or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param from The owner of the tokens.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function compatTransferFrom(IERC20Token token, address from, address to, uint256 amount) internal {
|
||||
bytes memory callData = abi.encodeCall(token.transferFrom, (from, to, amount));
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Retrieves the number of decimals for a token.
|
||||
/// Returns `18` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @return tokenDecimals The number of decimals places for the token.
|
||||
function compatDecimals(IERC20Token token) internal view returns (uint8 tokenDecimals) {
|
||||
tokenDecimals = 18;
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
tokenDecimals = abi.decode(resultData, (uint8));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrieves the allowance for a token, owner, and spender.
|
||||
/// Returns `0` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @param spender The address the spender.
|
||||
/// @return allowance_ The allowance for a token, owner, and spender.
|
||||
function compatAllowance(
|
||||
IERC20Token token,
|
||||
address owner,
|
||||
address spender
|
||||
) internal view returns (uint256 allowance_) {
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
|
||||
abi.encodeCall(token.allowance, (owner, spender))
|
||||
);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
allowance_ = abi.decode(resultData, (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrieves the balance for a token owner.
|
||||
/// Returns `0` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @return balance The token balance of an owner.
|
||||
function compatBalanceOf(IERC20Token token, address owner) internal view returns (uint256 balance) {
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
|
||||
abi.encodeCall(token.balanceOf, (owner))
|
||||
);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
balance = abi.decode(resultData, (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Executes a call on address `target` with calldata `callData`
|
||||
/// and asserts that either nothing was returned or a single boolean
|
||||
/// was returned equal to `true`.
|
||||
/// @param target The call target.
|
||||
/// @param callData The abi-encoded call data.
|
||||
function _callWithOptionalBooleanResult(address target, bytes memory callData) private {
|
||||
(bool didSucceed, bytes memory resultData) = target.call(callData);
|
||||
// Revert if the call reverted.
|
||||
if (!didSucceed) {
|
||||
LibRichErrorsV08.rrevert(resultData);
|
||||
}
|
||||
// If we get back 0 returndata, this may be a non-standard ERC-20 that
|
||||
// does not return a boolean. Check that it at least contains code.
|
||||
if (resultData.length == 0) {
|
||||
require(target.code.length > 0, "invalid token address, contains no code");
|
||||
return;
|
||||
}
|
||||
// If we get back at least 32 bytes, we know the target address
|
||||
// contains code, and we assume it is a token that returned a boolean
|
||||
// success value, which must be true.
|
||||
if (resultData.length >= 32) {
|
||||
if (!abi.decode(resultData, (bool))) {
|
||||
LibRichErrorsV08.rrevert(resultData);
|
||||
}
|
||||
}
|
||||
// If 0 < returndatasize < 32, the target is a contract, but not a
|
||||
// valid token.
|
||||
LibRichErrorsV08.rrevert(resultData);
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/dummy_erc20_token';
|
||||
export * from '../generated-wrappers/dummy_multiple_return_erc20_token';
|
||||
export * from '../generated-wrappers/dummy_no_return_erc20_token';
|
||||
export * from '../generated-wrappers/erc20_token';
|
||||
export * from '../generated-wrappers/weth9';
|
||||
export * from '../generated-wrappers/zrx_token';
|
73
contracts/erc20/test/WETH9V06Test.t.sol
Normal file
73
contracts/erc20/test/WETH9V06Test.t.sol
Normal file
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright 2023 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.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "../src/v06/WETH9V06.sol";
|
||||
|
||||
contract WETH9V06Test is Test {
|
||||
address payable internal owner = payable(vm.addr(1));
|
||||
address payable internal user = payable(vm.addr(2));
|
||||
WETH9V06 internal etherToken;
|
||||
|
||||
function setUp() public {
|
||||
vm.deal(owner, 1e20);
|
||||
vm.deal(user, 1e20);
|
||||
|
||||
etherToken = new WETH9V06();
|
||||
}
|
||||
|
||||
function testShouldRevertIfCallerAttemptsToDepositMoreThanTheirBalance() public {
|
||||
vm.prank(user);
|
||||
vm.expectRevert();
|
||||
etherToken.deposit{value: 1e20 + 1}();
|
||||
}
|
||||
|
||||
function testShouldConvertDepositedETHToWrappedETH() public {
|
||||
vm.prank(user);
|
||||
etherToken.deposit{value: 1e20}();
|
||||
|
||||
assertEq(etherToken.balanceOf(user), 1e20);
|
||||
assertEq(address(etherToken).balance, 1e20);
|
||||
}
|
||||
|
||||
function testShouldRevertIfCallerAttemptsToWithdrawMoreThanTheirBalance() public {
|
||||
vm.prank(user);
|
||||
etherToken.deposit{value: 1e20}();
|
||||
|
||||
vm.expectRevert();
|
||||
etherToken.withdraw(1e20 + 1);
|
||||
}
|
||||
|
||||
function testShouldConvertWithdrawWrappedETHToETH() public {
|
||||
vm.prank(user);
|
||||
etherToken.deposit{value: 1e20}();
|
||||
vm.prank(user);
|
||||
etherToken.withdraw(100);
|
||||
|
||||
assertEq(etherToken.balanceOf(user), 1e20 - 100);
|
||||
assertEq(address(etherToken).balance, 1e20 - 100);
|
||||
assertEq(user.balance, 100);
|
||||
}
|
||||
|
||||
function testShouldConvertSentETHToWrappedETH() public {
|
||||
vm.prank(user);
|
||||
address(etherToken).call{value: 1e20}(new bytes(0));
|
||||
|
||||
assertEq(etherToken.balanceOf(user), 1e20);
|
||||
assertEq(address(etherToken).balance, 1e20);
|
||||
}
|
||||
}
|
112
contracts/erc20/test/ZRXTokenTest.t.sol
Normal file
112
contracts/erc20/test/ZRXTokenTest.t.sol
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright 2023 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.8.17;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "../src/IERC20Token.sol";
|
||||
|
||||
contract ZRXTokenTest is Test {
|
||||
address payable internal owner = payable(vm.addr(1));
|
||||
address payable internal user = payable(vm.addr(2));
|
||||
address payable internal anotherUser = payable(vm.addr(3));
|
||||
uint256 internal totalSupply = 1_000_000_000 * 1e18;
|
||||
IERC20Token zrxToken;
|
||||
|
||||
function setUp() public {
|
||||
vm.deal(owner, 1e20);
|
||||
vm.deal(user, 1e20);
|
||||
|
||||
vm.prank(owner);
|
||||
bytes memory _bytecode = vm.getCode("./out/ZRXToken.sol/ZRXToken.json");
|
||||
address _address;
|
||||
assembly {
|
||||
_address := create(0, add(_bytecode, 0x20), mload(_bytecode))
|
||||
}
|
||||
zrxToken = IERC20Token(address(_address));
|
||||
}
|
||||
|
||||
function testShouldHave18Decimals() public {
|
||||
assertEq(zrxToken.decimals(), 18);
|
||||
}
|
||||
|
||||
function testShouldHaveTotalSupplyOf1Billion() public {
|
||||
assertEq(zrxToken.totalSupply(), totalSupply);
|
||||
}
|
||||
|
||||
function testShouldInitializeOwnerBalanceToTotalSupply() public {
|
||||
assertEq(zrxToken.balanceOf(owner), totalSupply);
|
||||
}
|
||||
|
||||
function testShouldTransferBalanceCorrectly() public {
|
||||
vm.prank(owner);
|
||||
zrxToken.transfer(user, 100);
|
||||
|
||||
assertEq(zrxToken.balanceOf(user), 100);
|
||||
assertEq(zrxToken.balanceOf(owner), totalSupply - 100);
|
||||
}
|
||||
|
||||
function testShouldReturnTrueOnAZeroValueTransfer() public {
|
||||
vm.prank(owner);
|
||||
bool success = zrxToken.transfer(user, 0);
|
||||
assertTrue(success);
|
||||
}
|
||||
|
||||
function testShouldReturnTrueOnAZeroValueTransferByUserWithZeroBalance() public {
|
||||
vm.prank(anotherUser);
|
||||
bool success = zrxToken.transfer(user, 0);
|
||||
assertTrue(success);
|
||||
}
|
||||
|
||||
function testShouldReturnFalseIfSenderHasInsufficientBalance() public {
|
||||
vm.prank(owner);
|
||||
zrxToken.approve(user, totalSupply + 1);
|
||||
|
||||
bool success = zrxToken.transferFrom(owner, user, totalSupply + 1);
|
||||
assertEq(success, false);
|
||||
}
|
||||
|
||||
function testShouldReturnFalseIfRecipientHasInsufficientAllowance() public {
|
||||
vm.prank(owner);
|
||||
zrxToken.approve(user, totalSupply - 1);
|
||||
|
||||
bool success = zrxToken.transferFrom(owner, user, totalSupply);
|
||||
assertEq(success, false);
|
||||
}
|
||||
|
||||
function testShouldReturnTrueOnAZeroValueApprovedTransfer() public {
|
||||
vm.prank(user);
|
||||
bool success = zrxToken.transferFrom(owner, user, 0);
|
||||
assertEq(success, true);
|
||||
}
|
||||
|
||||
function testShouldNotModifySenderAllowanceIfSetToUINT256Max() public {
|
||||
vm.prank(owner);
|
||||
zrxToken.approve(user, type(uint256).max);
|
||||
|
||||
zrxToken.transferFrom(owner, user, 100);
|
||||
assertEq(zrxToken.allowance(owner, user), type(uint256).max);
|
||||
}
|
||||
|
||||
function testShouldTransferCorrectlyWhenSufficientAllowance() public {
|
||||
vm.prank(owner);
|
||||
zrxToken.approve(user, 1000 * 1e18);
|
||||
|
||||
vm.prank(user);
|
||||
zrxToken.transferFrom(owner, user, 100 * 1e18);
|
||||
assertEq(zrxToken.allowance(owner, user), 900 * 1e18);
|
||||
assertEq(zrxToken.balanceOf(user), 100 * 1e18);
|
||||
assertEq(zrxToken.balanceOf(owner), totalSupply - 100 * 1e18);
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as DummyERC20Token from '../test/generated-artifacts/DummyERC20Token.json';
|
||||
import * as DummyMultipleReturnERC20Token from '../test/generated-artifacts/DummyMultipleReturnERC20Token.json';
|
||||
import * as DummyNoReturnERC20Token from '../test/generated-artifacts/DummyNoReturnERC20Token.json';
|
||||
import * as ERC20Token from '../test/generated-artifacts/ERC20Token.json';
|
||||
import * as IERC20Token from '../test/generated-artifacts/IERC20Token.json';
|
||||
import * as IERC20TokenV06 from '../test/generated-artifacts/IERC20TokenV06.json';
|
||||
import * as IEtherToken from '../test/generated-artifacts/IEtherToken.json';
|
||||
import * as IEtherTokenV06 from '../test/generated-artifacts/IEtherTokenV06.json';
|
||||
import * as LibERC20Token from '../test/generated-artifacts/LibERC20Token.json';
|
||||
import * as LibERC20TokenV06 from '../test/generated-artifacts/LibERC20TokenV06.json';
|
||||
import * as MintableERC20Token from '../test/generated-artifacts/MintableERC20Token.json';
|
||||
import * as TestLibERC20Token from '../test/generated-artifacts/TestLibERC20Token.json';
|
||||
import * as TestLibERC20TokenTarget from '../test/generated-artifacts/TestLibERC20TokenTarget.json';
|
||||
import * as UnlimitedAllowanceERC20Token from '../test/generated-artifacts/UnlimitedAllowanceERC20Token.json';
|
||||
import * as UntransferrableDummyERC20Token from '../test/generated-artifacts/UntransferrableDummyERC20Token.json';
|
||||
import * as WETH9 from '../test/generated-artifacts/WETH9.json';
|
||||
import * as ZRXToken from '../test/generated-artifacts/ZRXToken.json';
|
||||
export const artifacts = {
|
||||
ERC20Token: ERC20Token as ContractArtifact,
|
||||
LibERC20Token: LibERC20Token as ContractArtifact,
|
||||
MintableERC20Token: MintableERC20Token as ContractArtifact,
|
||||
UnlimitedAllowanceERC20Token: UnlimitedAllowanceERC20Token as ContractArtifact,
|
||||
WETH9: WETH9 as ContractArtifact,
|
||||
ZRXToken: (ZRXToken as any) as ContractArtifact,
|
||||
IERC20Token: IERC20Token as ContractArtifact,
|
||||
IEtherToken: IEtherToken as ContractArtifact,
|
||||
IERC20TokenV06: IERC20TokenV06 as ContractArtifact,
|
||||
IEtherTokenV06: IEtherTokenV06 as ContractArtifact,
|
||||
LibERC20TokenV06: LibERC20TokenV06 as ContractArtifact,
|
||||
DummyERC20Token: DummyERC20Token as ContractArtifact,
|
||||
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
|
||||
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
|
||||
TestLibERC20Token: TestLibERC20Token as ContractArtifact,
|
||||
TestLibERC20TokenTarget: TestLibERC20TokenTarget as ContractArtifact,
|
||||
UntransferrableDummyERC20Token: UntransferrableDummyERC20Token as ContractArtifact,
|
||||
};
|
@@ -1,19 +0,0 @@
|
||||
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();
|
||||
});
|
@@ -1,335 +0,0 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
|
||||
|
||||
import { TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from './wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
blockchainTests('LibERC20Token', env => {
|
||||
let testContract: TestLibERC20TokenContract;
|
||||
const REVERT_STRING = 'WHOOPSIE';
|
||||
const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
|
||||
const ENCODED_TRUE = hexUtils.leftPad(1);
|
||||
const ENCODED_FALSE = hexUtils.leftPad(0);
|
||||
const ENCODED_TWO = hexUtils.leftPad(2);
|
||||
const ENCODED_SHORT_TRUE = hexUtils.leftPad(2, 31);
|
||||
const ENCODED_LONG_TRUE = hexUtils.leftPad(2, 33);
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLibERC20Token,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('approve()', () => {
|
||||
it('calls the target with the correct arguments', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const { logs } = await testContract
|
||||
.testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
expect(logs).to.be.length(1);
|
||||
verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
|
||||
});
|
||||
|
||||
it('succeeds if the target returns true', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
await testContract
|
||||
.testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('succeeds if the target returns nothing', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
await testContract
|
||||
.testApprove(false, ENCODED_REVERT, constants.NULL_BYTES, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('fails if the target returns false', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testApprove(false, ENCODED_REVERT, ENCODED_FALSE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns nonzero and not true', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testApprove(false, ENCODED_REVERT, ENCODED_TWO, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns less than 32 bytes', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testApprove(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns greater than 32 bytes', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testApprove(false, ENCODED_REVERT, ENCODED_LONG_TRUE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target reverts', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testApprove(true, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(REVERT_STRING);
|
||||
});
|
||||
|
||||
it('fails if the target reverts with no data', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testApprove(true, constants.NULL_BYTES, ENCODED_TRUE, spender, allowance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.be.rejectedWith('revert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('transfer()', () => {
|
||||
it('calls the target with the correct arguments', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const { logs } = await testContract
|
||||
.testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
expect(logs).to.be.length(1);
|
||||
verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
|
||||
});
|
||||
|
||||
it('succeeds if the target returns true', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract
|
||||
.testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('succeeds if the target returns nothing', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract
|
||||
.testTransfer(false, ENCODED_REVERT, constants.NULL_BYTES, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('fails if the target returns false', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransfer(false, ENCODED_REVERT, ENCODED_FALSE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns nonzero and not true', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransfer(false, ENCODED_REVERT, ENCODED_TWO, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns less than 32 bytes', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransfer(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns greater than 32 bytes', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransfer(false, ENCODED_REVERT, ENCODED_LONG_TRUE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target reverts', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransfer(true, ENCODED_REVERT, ENCODED_TRUE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(REVERT_STRING);
|
||||
});
|
||||
|
||||
it('fails if the target reverts with no data', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransfer(true, constants.NULL_BYTES, ENCODED_TRUE, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.be.rejectedWith('revert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferFrom()', () => {
|
||||
it('calls the target with the correct arguments', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const { logs } = await testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
expect(logs).to.be.length(1);
|
||||
verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
|
||||
});
|
||||
|
||||
it('succeeds if the target returns true', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('succeeds if the target returns nothing', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, constants.NULL_BYTES, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('fails if the target returns false', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, ENCODED_FALSE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns nonzero and not true', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TWO, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns less than 32 bytes', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns greater than 32 bytes', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransferFrom(false, ENCODED_REVERT, ENCODED_LONG_TRUE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target reverts', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransferFrom(true, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.revertWith(REVERT_STRING);
|
||||
});
|
||||
|
||||
it('fails if the target reverts with no data', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract
|
||||
.testTransferFrom(true, constants.NULL_BYTES, ENCODED_TRUE, owner, to, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.be.rejectedWith('revert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('decimals()', () => {
|
||||
const DEFAULT_DECIMALS = 18;
|
||||
const ENCODED_ZERO = hexUtils.leftPad(0);
|
||||
const ENCODED_SHORT_ZERO = hexUtils.leftPad(0, 31);
|
||||
const ENCODED_LONG_ZERO = hexUtils.leftPad(0, 33);
|
||||
const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
|
||||
|
||||
it('returns the number of decimals defined by the token', async () => {
|
||||
const decimals = randomDecimals();
|
||||
const encodedDecimals = hexUtils.leftPad(decimals);
|
||||
const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
|
||||
return expect(result).to.bignumber.eq(decimals);
|
||||
});
|
||||
|
||||
it('returns 0 if the token returns 0', async () => {
|
||||
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_ZERO).callAsync();
|
||||
return expect(result).to.bignumber.eq(0);
|
||||
});
|
||||
|
||||
it('returns 18 if the token returns less than 32 bytes', async () => {
|
||||
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_SHORT_ZERO).callAsync();
|
||||
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
|
||||
});
|
||||
|
||||
it('returns 18 if the token returns greater than 32 bytes', async () => {
|
||||
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_LONG_ZERO).callAsync();
|
||||
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
|
||||
});
|
||||
|
||||
it('returns 18 if the token reverts', async () => {
|
||||
const result = await testContract.testDecimals(true, ENCODED_REVERT, ENCODED_ZERO).callAsync();
|
||||
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,187 +0,0 @@
|
||||
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { DummyERC20TokenContract } from './wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('UnlimitedAllowanceToken', () => {
|
||||
let owner: string;
|
||||
let spender: string;
|
||||
const MAX_MINT_VALUE = new BigNumber(10000000000000000000000);
|
||||
let token: DummyERC20TokenContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
spender = accounts[1];
|
||||
token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.DummyERC20Token,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
constants.DUMMY_TOKEN_NAME,
|
||||
constants.DUMMY_TOKEN_SYMBOL,
|
||||
constants.DUMMY_TOKEN_DECIMALS,
|
||||
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.mint(MAX_MINT_VALUE).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('transfer', () => {
|
||||
it('should revert if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
return expect(token.transfer(spender, amountToTransfer).callAsync({ from: owner })).to.revertWith(
|
||||
RevertReason.Erc20InsufficientBalance,
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer balance from sender to receiver', async () => {
|
||||
const receiver = spender;
|
||||
const initOwnerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = new BigNumber(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.transfer(receiver, amountToTransfer).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const finalOwnerBalance = await token.balanceOf(owner).callAsync();
|
||||
const finalReceiverBalance = await token.balanceOf(receiver).callAsync();
|
||||
|
||||
const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
|
||||
const expectedFinalReceiverBalance = amountToTransfer;
|
||||
expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
|
||||
expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
|
||||
});
|
||||
|
||||
it('should return true on a 0 value transfer', async () => {
|
||||
const didReturnTrue = await token.transfer(spender, new BigNumber(0)).callAsync({
|
||||
from: owner,
|
||||
});
|
||||
expect(didReturnTrue).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferFrom', () => {
|
||||
it('should revert if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.approve(spender, amountToTransfer).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
return expect(
|
||||
token.transferFrom(owner, spender, amountToTransfer).callAsync({
|
||||
from: spender,
|
||||
}),
|
||||
).to.revertWith(RevertReason.Erc20InsufficientBalance);
|
||||
});
|
||||
|
||||
it('should revert if spender has insufficient allowance', async () => {
|
||||
const ownerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = ownerBalance;
|
||||
|
||||
const spenderAllowance = await token.allowance(owner, spender).callAsync();
|
||||
const isSpenderAllowanceInsufficient = spenderAllowance.comparedTo(amountToTransfer) < 0;
|
||||
expect(isSpenderAllowanceInsufficient).to.be.true();
|
||||
|
||||
return expect(
|
||||
token.transferFrom(owner, spender, amountToTransfer).callAsync({
|
||||
from: spender,
|
||||
}),
|
||||
).to.revertWith(RevertReason.Erc20InsufficientAllowance);
|
||||
});
|
||||
|
||||
it('should return true on a 0 value transfer', async () => {
|
||||
const amountToTransfer = new BigNumber(0);
|
||||
const didReturnTrue = await token.transferFrom(owner, spender, amountToTransfer).callAsync({
|
||||
from: spender,
|
||||
});
|
||||
expect(didReturnTrue).to.be.true();
|
||||
});
|
||||
|
||||
it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
|
||||
const initOwnerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await token.allowance(owner, spender).callAsync();
|
||||
expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
|
||||
});
|
||||
|
||||
it('should transfer the correct balances if spender has sufficient allowance', async () => {
|
||||
const initOwnerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = initOwnerBalance;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newOwnerBalance = await token.balanceOf(owner).callAsync();
|
||||
const newSpenderBalance = await token.balanceOf(spender).callAsync();
|
||||
|
||||
expect(newOwnerBalance).to.be.bignumber.equal(0);
|
||||
expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance);
|
||||
});
|
||||
|
||||
it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
|
||||
const initOwnerBalance = await token.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = initOwnerBalance;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await token.allowance(owner, spender).callAsync();
|
||||
expect(newSpenderAllowance).to.be.bignumber.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,149 +0,0 @@
|
||||
import {
|
||||
chaiSetup,
|
||||
constants,
|
||||
expectInsufficientFundsAsync,
|
||||
expectTransactionFailedWithoutReasonAsync,
|
||||
provider,
|
||||
txDefaults,
|
||||
web3Wrapper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { WETH9Contract } from './wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('EtherToken', () => {
|
||||
let account: string;
|
||||
const gasPrice = new BigNumber(constants.DEFAULT_GAS_PRICE);
|
||||
let etherToken: WETH9Contract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
account = accounts[0];
|
||||
|
||||
etherToken = await WETH9Contract.deployFrom0xArtifactAsync(
|
||||
artifacts.WETH9,
|
||||
provider,
|
||||
{
|
||||
...txDefaults,
|
||||
gasPrice,
|
||||
},
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('deposit', () => {
|
||||
it('should revert if caller attempts to deposit more Ether than caller balance', async () => {
|
||||
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const ethToDeposit = initEthBalance.plus(1);
|
||||
|
||||
return expectInsufficientFundsAsync(etherToken.deposit().sendTransactionAsync({ value: ethToDeposit }));
|
||||
});
|
||||
|
||||
it('should convert deposited Ether to wrapped Ether tokens', async () => {
|
||||
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
|
||||
const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
|
||||
|
||||
const txHash = await etherToken.deposit().sendTransactionAsync({ value: ethToDeposit });
|
||||
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
txHash,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
|
||||
const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
|
||||
expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
|
||||
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
|
||||
});
|
||||
});
|
||||
|
||||
describe('withdraw', () => {
|
||||
it('should revert if caller attempts to withdraw greater than caller balance', async () => {
|
||||
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
const ethTokensToWithdraw = initEthTokenBalance.plus(1);
|
||||
|
||||
return expectTransactionFailedWithoutReasonAsync(
|
||||
etherToken.withdraw(ethTokensToWithdraw).sendTransactionAsync(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should convert ether tokens to ether with sufficient balance', async () => {
|
||||
const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await etherToken.deposit().sendTransactionAsync({ value: ethToDeposit }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const ethTokensToWithdraw = initEthTokenBalance;
|
||||
expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0);
|
||||
const txHash = await etherToken.withdraw(ethTokensToWithdraw).sendTransactionAsync({
|
||||
gas: constants.MAX_ETHERTOKEN_WITHDRAW_GAS,
|
||||
});
|
||||
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
txHash,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
|
||||
const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
|
||||
expect(finalEthBalance).to.be.bignumber.equal(
|
||||
initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)),
|
||||
);
|
||||
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw));
|
||||
});
|
||||
});
|
||||
|
||||
describe('fallback', () => {
|
||||
it('should convert sent ether to ether tokens', async () => {
|
||||
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
|
||||
const ethToDeposit = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18);
|
||||
|
||||
const txHash = await web3Wrapper.sendTransactionAsync({
|
||||
from: account,
|
||||
to: etherToken.address,
|
||||
value: ethToDeposit,
|
||||
gasPrice,
|
||||
});
|
||||
|
||||
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
txHash,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
|
||||
const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
|
||||
|
||||
expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
|
||||
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/dummy_erc20_token';
|
||||
export * from '../test/generated-wrappers/dummy_multiple_return_erc20_token';
|
||||
export * from '../test/generated-wrappers/dummy_no_return_erc20_token';
|
||||
export * from '../test/generated-wrappers/erc20_token';
|
||||
export * from '../test/generated-wrappers/i_erc20_token';
|
||||
export * from '../test/generated-wrappers/i_erc20_token_v06';
|
||||
export * from '../test/generated-wrappers/i_ether_token';
|
||||
export * from '../test/generated-wrappers/i_ether_token_v06';
|
||||
export * from '../test/generated-wrappers/lib_erc20_token';
|
||||
export * from '../test/generated-wrappers/lib_erc20_token_v06';
|
||||
export * from '../test/generated-wrappers/mintable_erc20_token';
|
||||
export * from '../test/generated-wrappers/test_lib_erc20_token';
|
||||
export * from '../test/generated-wrappers/test_lib_erc20_token_target';
|
||||
export * from '../test/generated-wrappers/unlimited_allowance_erc20_token';
|
||||
export * from '../test/generated-wrappers/untransferrable_dummy_erc20_token';
|
||||
export * from '../test/generated-wrappers/weth9';
|
||||
export * from '../test/generated-wrappers/zrx_token';
|
@@ -1,210 +0,0 @@
|
||||
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { ZRXTokenContract } from './wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('ZRXToken', () => {
|
||||
let owner: string;
|
||||
let spender: string;
|
||||
let MAX_UINT: BigNumber;
|
||||
let zrxToken: ZRXTokenContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
spender = accounts[1];
|
||||
zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ZRXToken,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
MAX_UINT = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('constants', () => {
|
||||
it('should have 18 decimals', async () => {
|
||||
const decimals = new BigNumber(await zrxToken.decimals().callAsync());
|
||||
const expectedDecimals = 18;
|
||||
expect(decimals).to.be.bignumber.equal(expectedDecimals);
|
||||
});
|
||||
|
||||
it('should have a total supply of 1 billion tokens', async () => {
|
||||
const totalSupply = new BigNumber(await zrxToken.totalSupply().callAsync());
|
||||
const expectedTotalSupply = 1000000000;
|
||||
expect(Web3Wrapper.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply);
|
||||
});
|
||||
|
||||
it('should be named 0x Protocol Token', async () => {
|
||||
const name = await zrxToken.name().callAsync();
|
||||
const expectedName = '0x Protocol Token';
|
||||
expect(name).to.be.equal(expectedName);
|
||||
});
|
||||
|
||||
it('should have the symbol ZRX', async () => {
|
||||
const symbol = await zrxToken.symbol().callAsync();
|
||||
const expectedSymbol = 'ZRX';
|
||||
expect(symbol).to.be.equal(expectedSymbol);
|
||||
});
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should initialize owner balance to totalSupply', async () => {
|
||||
const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const totalSupply = new BigNumber(await zrxToken.totalSupply().callAsync());
|
||||
expect(totalSupply).to.be.bignumber.equal(ownerBalance);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transfer', () => {
|
||||
it('should transfer balance from sender to receiver', async () => {
|
||||
const receiver = spender;
|
||||
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = new BigNumber(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transfer(receiver, amountToTransfer).sendTransactionAsync({ from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const finalOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const finalReceiverBalance = await zrxToken.balanceOf(receiver).callAsync();
|
||||
|
||||
const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
|
||||
const expectedFinalReceiverBalance = amountToTransfer;
|
||||
expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
|
||||
expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
|
||||
});
|
||||
|
||||
it('should return true on a 0 value transfer', async () => {
|
||||
const didReturnTrue = await zrxToken.transfer(spender, new BigNumber(0)).callAsync({
|
||||
from: owner,
|
||||
});
|
||||
expect(didReturnTrue).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferFrom', () => {
|
||||
it('should return false if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve(spender, amountToTransfer).sendTransactionAsync({
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
|
||||
from: spender,
|
||||
});
|
||||
expect(didReturnTrue).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false if spender has insufficient allowance', async () => {
|
||||
const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = ownerBalance;
|
||||
|
||||
const spenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
|
||||
const isSpenderAllowanceInsufficient = spenderAllowance.comparedTo(amountToTransfer) < 0;
|
||||
expect(isSpenderAllowanceInsufficient).to.be.true();
|
||||
|
||||
const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
|
||||
from: spender,
|
||||
});
|
||||
expect(didReturnTrue).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true on a 0 value transfer', async () => {
|
||||
const amountToTransfer = new BigNumber(0);
|
||||
const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
|
||||
from: spender,
|
||||
});
|
||||
expect(didReturnTrue).to.be.true();
|
||||
});
|
||||
|
||||
it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = MAX_UINT;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve(spender, initSpenderAllowance).sendTransactionAsync({
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
|
||||
expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
|
||||
});
|
||||
|
||||
it('should transfer the correct balances if spender has sufficient allowance', async () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const initSpenderBalance = await zrxToken.balanceOf(spender).callAsync();
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = initOwnerBalance;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve(spender, initSpenderAllowance).sendTransactionAsync(),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const newSpenderBalance = await zrxToken.balanceOf(spender).callAsync();
|
||||
|
||||
expect(newOwnerBalance).to.be.bignumber.equal(0);
|
||||
expect(newSpenderBalance).to.be.bignumber.equal(initSpenderBalance.plus(initOwnerBalance));
|
||||
});
|
||||
|
||||
it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve(spender, amountToTransfer).sendTransactionAsync(),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
|
||||
expect(newSpenderAllowance).to.be.bignumber.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
// development: {
|
||||
// host: "127.0.0.1", // Localhost (default: none)
|
||||
// port: 8545, // Standard Ethereum port (default: none)
|
||||
// network_id: "*", // Any network (default: none)
|
||||
// },
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/DummyERC20Token.json",
|
||||
"generated-artifacts/DummyMultipleReturnERC20Token.json",
|
||||
"generated-artifacts/DummyNoReturnERC20Token.json",
|
||||
"generated-artifacts/ERC20Token.json",
|
||||
"generated-artifacts/WETH9.json",
|
||||
"generated-artifacts/ZRXToken.json",
|
||||
"test/generated-artifacts/DummyERC20Token.json",
|
||||
"test/generated-artifacts/DummyMultipleReturnERC20Token.json",
|
||||
"test/generated-artifacts/DummyNoReturnERC20Token.json",
|
||||
"test/generated-artifacts/ERC20Token.json",
|
||||
"test/generated-artifacts/IERC20Token.json",
|
||||
"test/generated-artifacts/IERC20TokenV06.json",
|
||||
"test/generated-artifacts/IEtherToken.json",
|
||||
"test/generated-artifacts/IEtherTokenV06.json",
|
||||
"test/generated-artifacts/LibERC20Token.json",
|
||||
"test/generated-artifacts/LibERC20TokenV06.json",
|
||||
"test/generated-artifacts/MintableERC20Token.json",
|
||||
"test/generated-artifacts/TestLibERC20Token.json",
|
||||
"test/generated-artifacts/TestLibERC20TokenTarget.json",
|
||||
"test/generated-artifacts/UnlimitedAllowanceERC20Token.json",
|
||||
"test/generated-artifacts/UntransferrableDummyERC20Token.json",
|
||||
"test/generated-artifacts/WETH9.json",
|
||||
"test/generated-artifacts/ZRXToken.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false
|
||||
}
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
47
contracts/governance/CHANGELOG.json
Normal file
47
contracts/governance/CHANGELOG.json
Normal file
@@ -0,0 +1,47 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1682976338,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1681756154,
|
||||
"version": "1.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1681694690,
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1681687842,
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1681157139,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
26
contracts/governance/CHANGELOG.md
Normal file
26
contracts/governance/CHANGELOG.md
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||
Edit the package's CHANGELOG.json file only.
|
||||
-->
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.5 - _May 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.4 - _April 17, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.3 - _April 17, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.2 - _April 16, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1 - _April 10, 2023_
|
||||
|
||||
* Dependencies updated
|
74
contracts/governance/README.md
Normal file
74
contracts/governance/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
## Governance
|
||||
|
||||
This package contains contracts for the ZeroEx governance of 0x Protocol and Treasury.
|
||||
|
||||
## Production deployment
|
||||
|
||||
`ZRXWrappedToken` 0xfcfaf7834f134f5146dbb3274bab9bed4bafa917
|
||||
`ZeroExVotesProxy` 0x9c766e51b46cbc1fa4f8b6718ed4a60ac9d591fb
|
||||
`ZeroExVotes` 0x8d208c5514b98c5b9ceed650b02df2aeb1c73e6f
|
||||
Protocol `ZeroExTimelock` 0xb6a1f58c5df9f13312639cddda0d128bf28cdd87
|
||||
`ZeroExProtocolGovernor` 0xc256035fe8533f9ce362012a6ae0aefed4df30f4
|
||||
Treasury `ZeroExTimelock` 0x0dcfb77a581bc8fe432e904643a5480cc183f38d
|
||||
`ZeroExTreasuryGovernor` 0x4822cfc1e7699bdb9551bdfd3a838ee414bc2008
|
||||
Security council 0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F
|
||||
|
||||
## Design
|
||||
|
||||
This implementation fully decentralises governance of 0x Protocol and Treasury. This is enabled via a wrapped ZRX token and a Compound-like governors design. There are two separate governors for Protocol - `ZeroExProtocolGovernor` and Treasury - `ZeroExTreasuryGovernor` respectively working with two separate Timelock instances of the same contract implementation - `ZeroExTimelock`.
|
||||
|
||||
### Upgradability
|
||||
`ZRXWrappedToken` , `ZeroExProtocolGovernor` and `ZeroExTreasuryGovernor` governors are non-upgradable by design. However the voting implementation the governors use - `ZeroExVotes` is upgradable and using the OZ `ERC1967Proxy`.
|
||||
|
||||
### Wrapped ZRX
|
||||
wZRX will be issued 1-to-1 for ZRX. No locking/vesting mechanisms will exist between wZRX and ZRX and the two will be freely interchangeable. The ZRX token is non-upgradable and same will be valid for its wrapped equivalent.
|
||||
|
||||
The token supports delegation which allows a user to delegate their entire voting power to another account (which doesn't necessarily need to be a token holder). This is modelled on the standard OpenZeppelin `ERC20Votes` implementation. We have added logic for block number stamping delegators' balance changes stored in the `DelegateInfo.balanceLastUpdated` property. This block number information is sent in calls to `ZeroExVotes.moveVotingPower` in order to provide support for future upgrades to the vote power calculation.
|
||||
Note that for consistency `block.number` is used for the governor settings, voting checkpoints and this delegators' balance last updated property while timelock logic for the governor uses block.timestamp.
|
||||
|
||||
### Governors' settings
|
||||
Changing governors' settings for `votingDelay`, `votingPeriod` and `proposalThreshold` can be done via the normal proposal mechanism. Governors are deployed with the following initial settings:
|
||||
|
||||
| | voting delay | voting period | proposal threshold |
|
||||
|-------------------|--------------|---------------|--------------------|
|
||||
| Protocol governor | 2 days | 7 days | 1000000e18 |
|
||||
| Treasury governor | 2 days | 7 days | 250000e18 |
|
||||
|
||||
|
||||
This is using standard openzeppelin `GovernorSettings` implementation.
|
||||
|
||||
### Quorum
|
||||
Quorum for Protocol is fixed at 10m (10000000e18) while for Treasury this is calculated as 10% of voting power of the total supply (see voting strategies below for quadratic voting power implementation specifics). The quorum calculations for Treasury are using OpenZeppelin's `GovernorVotesQuorumFraction`.
|
||||
|
||||
Note that in-place updates to the quorum are not supported and will need to go through a governance upgrade. Reasoning behind this can be found in this discussion https://forum.openzeppelin.com/t/quorum-default-behaviour-on-governors/34560.
|
||||
|
||||
### Voting strategies
|
||||
The voting strategy will be linear 1-token-1-vote for Protocol and quadratic with threshold of 1000000e18 for Treasury (i.e. voting weight is linear up to 1m tokens and balance above that threshold is quadratic).
|
||||
|
||||
Worth noting is the `Checkpoint` struct design. For packing every `Checkpoint` into a single storage slot we are using the minimum uint type size for `votes` and `quadraticVotes` members, e.g.
|
||||
|
||||
```
|
||||
struct Checkpoint {
|
||||
uint32 fromBlock;
|
||||
uint96 votes;
|
||||
uint96 quadraticVotes;
|
||||
}
|
||||
```
|
||||
|
||||
since the maximum token supply is 1bn we can have maximum value for:
|
||||
`votes` : 1bn *10^18 => can be stored in 90 bits
|
||||
`quadraticVotes` : due to the likelihood of threshold changing and potentially bringing it closer to a linear vote, we are preemptively keeping this to the same size as linear votes slot.
|
||||
|
||||
### Time locks
|
||||
Governance proposals are subject to a 3 days delay for Protocol and 2 days for Treasury. This delay allows Security Council time to review passed proposals and take action where needed.
|
||||
|
||||
### Security Council
|
||||
The concept of a Security council is introduced which allows a multisig of security council members to cancel a proposal on the treasury or protocol governors and also rollback the protocol to an earlier version.
|
||||
|
||||
When no security council is assigned the following apply:
|
||||
|
||||
- ongoing proposals can still be voted on
|
||||
- new proposals cannot be created - except assignSecurityCouncil
|
||||
- expired proposals that are successful cannot be queued - excepted assignSecurityCouncil
|
||||
|
||||
There is a provision for the governors to have different security council set although initially these are the same.
|
505
contracts/governance/ZRXToken.json
Normal file
505
contracts/governance/ZRXToken.json
Normal file
@@ -0,0 +1,505 @@
|
||||
{
|
||||
"abi": [
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transfer",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_spender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "allowance",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"payable": false,
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "_from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "_spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
}
|
||||
],
|
||||
"bytecode": {
|
||||
"object": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b61078d8061004a6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058202dbef854545f38e5b78ec251d65db5fa0f12b6f2f0a0039063735c2dc416d6310029",
|
||||
"sourceMap": "4935:353:0:-;;;5056:8;5027:37;;5208:78;;;;;;;5268:11;;-1:-1:-1;;;;;5254:10:0;5245:20;:8;:20;;;;;;;;;;:34;5208:78;4935:353;;;;;;;",
|
||||
"linkReferences": {}
|
||||
},
|
||||
"deployedBytecode": {
|
||||
"object": "0x606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058202dbef854545f38e5b78ec251d65db5fa0f12b6f2f0a0039063735c2dc416d6310029",
|
||||
"sourceMap": "4935:353:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5109:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18:2:-1;;13:3;7:5;32;59:3;53:5;48:3;41:6;93:2;88:3;85:2;78:6;73:3;67:5;152:3;;;;;117:2;108:3;;;;130;172:5;167:4;181:3;3:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3523:190:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5027:37;;;;;;;;;;;;;;;;;;;;;;;;;;4369:562;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4986:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3415:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5164:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18:2:-1;;13:3;7:5;32;59:3;53:5;48:3;41:6;93:2;88:3;85:2;78:6;73:3;67:5;152:3;;;;;117:2;108:3;;;;130;172:5;167:4;181:3;3:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2490:433:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3719:129;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5109:49;;;;;;;;;;;;;;;;;;;:::o;3523:190::-;3599:19;3607:10;3599:19;;3583:4;3599:19;;;:7;:19;;;;;;;;:29;;;;;;;;;;;;:38;;;3647;;;;;;;3583:4;;3599:29;:19;3647:38;;;;;;;;;;;-1:-1:-1;3702:4:0;3523:190;;;;;:::o;5027:37::-;;;;:::o;4369:562::-;4487:14;;;;4451:4;4487:14;;;:7;:14;;;;;;;;4502:10;4487:26;;;;;;;;;;;;4527:15;;;;;;;;;;:25;;;;;;:48;;;4569:6;4556:9;:19;;4527:48;:91;;;;-1:-1:-1;4605:13:0;;;:8;:13;;;;;;;;;;;4579:22;;;:39;;4527:91;4523:402;;;4634:13;;;;:8;:13;;;;;;;;;;;:23;;;;;;4671:15;;;;;;:25;;;;;;;4069:12;4714:20;;4710:95;;;4754:14;;;;;;;;:7;:14;;;;;;;;4769:10;4754:26;;;;;;;;;:36;;;;;;;4710:95;4834:3;4818:28;;4827:5;4818:28;;;4839:6;4818:28;;;;;;;;;;;;;;;;;;4867:4;4860:11;;;;4523:402;4909:5;4902:12;;4523:402;4369:562;;;;;;;:::o;4986:35::-;5019:2;4986:35;:::o;3415:102::-;3494:16;;;3468:7;3494:16;;;;;;;;;;;3415:102;;;;:::o;5164:37::-;;;;;;;;;;;;;;;;;;;:::o;2490:433::-;2635:20;2644:10;2635:20;2546:4;2635:20;;;;;;;;;;;:30;;;;;;:73;;-1:-1:-1;2695:13:0;;;:8;:13;;;;;;;;;;;2669:22;;;:39;;2635:73;2631:286;;;2724:20;2733:10;2724:20;;:8;:20;;;;;;;;;;;:30;;;;;;;2768:13;;;;;;;;;;:23;;;;;;2805:33;;;;;;;2768:13;;2805:33;;;;;;;;;;;-1:-1:-1;2859:4:0;2852:11;;2631:286;-1:-1:-1;2901:5:0;2894:12;;2631:286;2490:433;;;;;:::o;3719:129::-;3816:15;;;;3790:7;3816:15;;;:7;:15;;;;;;;;:25;;;;;;;;;;3719:129;;;;;:::o",
|
||||
"linkReferences": {}
|
||||
},
|
||||
"methodIdentifiers": {
|
||||
"allowance(address,address)": "dd62ed3e",
|
||||
"approve(address,uint256)": "095ea7b3",
|
||||
"balanceOf(address)": "70a08231",
|
||||
"decimals()": "313ce567",
|
||||
"name()": "06fdde03",
|
||||
"symbol()": "95d89b41",
|
||||
"totalSupply()": "18160ddd",
|
||||
"transfer(address,uint256)": "a9059cbb",
|
||||
"transferFrom(address,address,uint256)": "23b872dd"
|
||||
},
|
||||
"rawMetadata": "{\"compiler\":{\"version\":\"0.4.11+commit.68ef5810\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"transferFrom(address,address,uint256)\":{\"details\":\"ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.\",\"params\":{\"_from\":\"Address to transfer from.\",\"_to\":\"Address to transfer to.\",\"_value\":\"Amount to transfer.\"},\"return\":\"Success of transfer.\"}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/erc20/src/ZRXToken.sol\":\"ZRXToken\"},\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@0x/contracts-erc20/=contracts/erc20/\",\":@0x/contracts-utils/=contracts/utils/\",\":ds-test/=contracts/erc20/lib/forge-std/lib/ds-test/src/\",\":forge-std/=contracts/erc20/lib/forge-std/src/\"]},\"sources\":{\"contracts/erc20/src/ZRXToken.sol\":{\"keccak256\":\"0x8582c06b20f8b7d3d603b485b5d26f840e01d1986381b334a856833edcff0d47\",\"urls\":[\"bzzr://ef728dddbaa1e26baa6cc9fe0f83de5055bc0b17dfe488018f4ee59d68ccb5dd\"]}},\"version\":1}",
|
||||
"metadata": {
|
||||
"compiler": {
|
||||
"version": "0.4.11+commit.68ef5810"
|
||||
},
|
||||
"language": "Solidity",
|
||||
"output": {
|
||||
"abi": [
|
||||
{
|
||||
"inputs": [],
|
||||
"type": "function",
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"type": "function",
|
||||
"name": "approve",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"type": "function",
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"type": "function",
|
||||
"name": "transferFrom",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"type": "function",
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"type": "function",
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"type": "function",
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"type": "function",
|
||||
"name": "transfer",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_spender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"type": "function",
|
||||
"name": "allowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_from",
|
||||
"type": "address",
|
||||
"indexed": true
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_to",
|
||||
"type": "address",
|
||||
"indexed": true
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_value",
|
||||
"type": "uint256",
|
||||
"indexed": false
|
||||
}
|
||||
],
|
||||
"type": "event",
|
||||
"name": "Transfer",
|
||||
"anonymous": false
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_owner",
|
||||
"type": "address",
|
||||
"indexed": true
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_spender",
|
||||
"type": "address",
|
||||
"indexed": true
|
||||
},
|
||||
{
|
||||
"internalType": null,
|
||||
"name": "_value",
|
||||
"type": "uint256",
|
||||
"indexed": false
|
||||
}
|
||||
],
|
||||
"type": "event",
|
||||
"name": "Approval",
|
||||
"anonymous": false
|
||||
}
|
||||
],
|
||||
"devdoc": {
|
||||
"methods": {
|
||||
"transferFrom(address,address,uint256)": {
|
||||
"details": "ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.",
|
||||
"params": {
|
||||
"_from": "Address to transfer from.",
|
||||
"_to": "Address to transfer to.",
|
||||
"_value": "Amount to transfer."
|
||||
},
|
||||
"return": "Success of transfer."
|
||||
}
|
||||
}
|
||||
},
|
||||
"userdoc": {
|
||||
"methods": {}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"remappings": [
|
||||
":@0x/contracts-erc20/=contracts/erc20/",
|
||||
":@0x/contracts-utils/=contracts/utils/",
|
||||
":ds-test/=contracts/erc20/lib/forge-std/lib/ds-test/src/",
|
||||
":forge-std/=contracts/erc20/lib/forge-std/src/"
|
||||
],
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000
|
||||
},
|
||||
"compilationTarget": {
|
||||
"contracts/erc20/src/ZRXToken.sol": "ZRXToken"
|
||||
},
|
||||
"libraries": {}
|
||||
},
|
||||
"sources": {
|
||||
"contracts/erc20/src/ZRXToken.sol": {
|
||||
"keccak256": "0x8582c06b20f8b7d3d603b485b5d26f840e01d1986381b334a856833edcff0d47",
|
||||
"urls": ["bzzr://ef728dddbaa1e26baa6cc9fe0f83de5055bc0b17dfe488018f4ee59d68ccb5dd"],
|
||||
"license": null
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
},
|
||||
"id": 0
|
||||
}
|
BIN
contracts/governance/audits/0xProtocol-06-04-2023-Final.pdf
Normal file
BIN
contracts/governance/audits/0xProtocol-06-04-2023-Final.pdf
Normal file
Binary file not shown.
BIN
contracts/governance/audits/OxProtocol-31-03-2023-Pre.pdf
Normal file
BIN
contracts/governance/audits/OxProtocol-31-03-2023-Pre.pdf
Normal file
Binary file not shown.
37
contracts/governance/foundry.toml
Normal file
37
contracts/governance/foundry.toml
Normal file
@@ -0,0 +1,37 @@
|
||||
[profile.default]
|
||||
src = 'src'
|
||||
out = 'out'
|
||||
libs = ['lib', "../utils/contracts/src/"]
|
||||
match_path = "test/unit/*.sol"
|
||||
fs_permissions = [{ access = "read", path = "./" }]
|
||||
remappings = [
|
||||
'@openzeppelin/=./lib/openzeppelin-contracts/contracts/',
|
||||
'@openzeppelin-contracts-upgradeable/=./lib/openzeppelin-contracts-upgradeable/contracts/',
|
||||
'@0x/contracts-utils/=../utils/',
|
||||
]
|
||||
solc = '0.8.19'
|
||||
optimizer_runs = 20_000
|
||||
via_ir = true
|
||||
|
||||
[profile.integration]
|
||||
match_path = "test/integration/*.sol"
|
||||
gas_price = 31_000_000_000
|
||||
|
||||
[rpc_endpoints]
|
||||
goerli = "${GOERLI_RPC_URL}"
|
||||
mainnet = "${MAINNET_RPC_URL}"
|
||||
|
||||
[etherscan]
|
||||
goerli = { key = "${ETHERSCAN_API_KEY}" }
|
||||
|
||||
[profile.smt.model_checker]
|
||||
engine = 'chc'
|
||||
timeout = 10_000
|
||||
targets = [
|
||||
'assert',
|
||||
'constantCondition',
|
||||
'divByZero',
|
||||
'outOfBounds',
|
||||
'underflow'
|
||||
]
|
||||
contracts = { 'src/ZeroExProtocolGovernor.sol' = [ 'ZeroExProtocolGovernor' ] }
|
1
contracts/governance/lib/forge-std
Submodule
1
contracts/governance/lib/forge-std
Submodule
Submodule contracts/governance/lib/forge-std added at eb980e1d4f
1
contracts/governance/lib/openzeppelin-contracts
Submodule
1
contracts/governance/lib/openzeppelin-contracts
Submodule
Submodule contracts/governance/lib/openzeppelin-contracts added at d00acef405
Submodule contracts/governance/lib/openzeppelin-contracts-upgradeable added at f6c4c9c4ec
27
contracts/governance/package.json
Normal file
27
contracts/governance/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@0x/governance",
|
||||
"version": "1.0.5",
|
||||
"description": "Governance implementation for the 0x protocol and treasury",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "forge test",
|
||||
"build": "forge build",
|
||||
"build:smt": "FOUNDRY_PROFILE=smt forge build",
|
||||
"test:integration": "source .env && FOUNDRY_PROFILE=integration forge test --fork-url $MAINNET_RPC_URL --fork-block-number 16884148 -vvv",
|
||||
"goerli:deploy:zrxtoken": "source .env && forge script script/DeployToken.s.sol:Deploy --rpc-url $GOERLI_RPC_URL --broadcast --slow -vvvv",
|
||||
"goerli:deploy:governance": "source .env && forge script script/DeployGovernance.s.sol:Deploy --rpc-url $GOERLI_RPC_URL --broadcast --slow -vvvv",
|
||||
"mainnet:deploy:governance": "source .env && forge script script/DeployGovernance.s.sol:Deploy --rpc-url $MAINNET_RPC_URL --broadcast --slow -vvvv"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"license": "Apache-2.0"
|
||||
}
|
80
contracts/governance/script/DeployGovernance.s.sol
Normal file
80
contracts/governance/script/DeployGovernance.s.sol
Normal file
@@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "forge-std/console.sol";
|
||||
import "forge-std/console2.sol";
|
||||
import "@openzeppelin/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
|
||||
|
||||
import "../src/ZRXWrappedToken.sol";
|
||||
import "../src/ZeroExVotes.sol";
|
||||
import "../src/ZeroExTimelock.sol";
|
||||
import "../src/ZeroExProtocolGovernor.sol";
|
||||
import "../src/ZeroExTreasuryGovernor.sol";
|
||||
|
||||
contract Deploy is Script {
|
||||
address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
|
||||
address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
|
||||
address internal constant EXCHANGE = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
|
||||
address payable internal constant SECURITY_COUNCIL = payable(0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F);
|
||||
uint256 internal constant QUADRATIC_THRESHOLD = 1000000e18;
|
||||
|
||||
function setUp() public {}
|
||||
|
||||
function run() external {
|
||||
address deployer = vm.envAddress("DEPLOYER");
|
||||
vm.startBroadcast(deployer);
|
||||
|
||||
console2.log("Zrx Token", ZRX_TOKEN);
|
||||
address wTokenPrediction = predict(deployer, vm.getNonce(deployer) + 2);
|
||||
ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, QUADRATIC_THRESHOLD);
|
||||
ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
|
||||
ZRXWrappedToken wToken = new ZRXWrappedToken(IERC20(ZRX_TOKEN), ZeroExVotes(address(votesProxy)));
|
||||
|
||||
assert(address(wToken) == wTokenPrediction);
|
||||
console2.log("Wrapped Token", address(wToken));
|
||||
|
||||
ZeroExVotes votes = ZeroExVotes(address(votesProxy));
|
||||
console2.log("Votes", address(votes));
|
||||
|
||||
address[] memory proposers = new address[](0);
|
||||
address[] memory executors = new address[](0);
|
||||
|
||||
ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, deployer);
|
||||
console2.log("Protocol timelock", address(protocolTimelock));
|
||||
|
||||
ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
|
||||
IVotes(address(votes)),
|
||||
protocolTimelock,
|
||||
SECURITY_COUNCIL
|
||||
);
|
||||
protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
|
||||
protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
|
||||
protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
|
||||
protocolTimelock.renounceRole(protocolTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
|
||||
console2.log("Protocol governor", address(protocolGovernor));
|
||||
|
||||
ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, deployer);
|
||||
console2.log("Treasury timelock", address(treasuryTimelock));
|
||||
|
||||
ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
|
||||
IVotes(address(votes)),
|
||||
treasuryTimelock,
|
||||
SECURITY_COUNCIL
|
||||
);
|
||||
|
||||
treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
|
||||
treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
|
||||
treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
|
||||
treasuryTimelock.renounceRole(treasuryTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
|
||||
console2.log("Treasury governor", address(treasuryGovernor));
|
||||
console2.log(unicode"0x governance deployed successfully 🎉");
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function predict(address deployer, uint256 nonce) internal pure returns (address) {
|
||||
require(nonce > 0 && nonce < 128, "Invalid nonce");
|
||||
return address(uint160(uint256(keccak256(abi.encodePacked(bytes2(0xd694), deployer, bytes1(uint8(nonce)))))));
|
||||
}
|
||||
}
|
22
contracts/governance/script/DeployToken.s.sol
Normal file
22
contracts/governance/script/DeployToken.s.sol
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "forge-std/console2.sol";
|
||||
|
||||
contract Deploy is Script {
|
||||
function setUp() public {}
|
||||
|
||||
function run() external {
|
||||
vm.startBroadcast(vm.envAddress("DEPLOYER"));
|
||||
|
||||
bytes memory _bytecode = vm.getCode("./ZRXToken.json");
|
||||
address zrxToken;
|
||||
assembly {
|
||||
zrxToken := create(0, add(_bytecode, 0x20), mload(_bytecode))
|
||||
}
|
||||
console2.log("Zrx Token", zrxToken);
|
||||
console2.log(unicode"Zrx Token deployed successfully 🎉");
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
169
contracts/governance/src/CallWithGas.sol
Normal file
169
contracts/governance/src/CallWithGas.sol
Normal file
@@ -0,0 +1,169 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.19;
|
||||
|
||||
library CallWithGas {
|
||||
/**
|
||||
* @notice `staticcall` another contract forwarding a precomputed amount of
|
||||
* gas.
|
||||
* @dev contains protections against EIP-150-induced insufficient gas
|
||||
* griefing
|
||||
* @dev reverts iff the target is not a contract or we encounter an
|
||||
* out-of-gas
|
||||
* @return success true iff the call succeded and returned no more than
|
||||
* `maxReturnBytes` of return data
|
||||
* @return returnData the return data or revert reason of the call
|
||||
* @param target the contract (reverts if non-contract) on which to make the
|
||||
* `staticcall`
|
||||
* @param data the calldata to pass
|
||||
* @param callGas the gas to pass for the call. If the call requires more than
|
||||
* the specified amount of gas and the caller didn't provide at
|
||||
* least `callGas`, triggers an out-of-gas in the caller.
|
||||
* @param maxReturnBytes Only this many bytes of return data are read back
|
||||
* from the call. This prevents griefing the caller. If
|
||||
* more bytes are returned or the revert reason is
|
||||
* longer, success will be false and returnData will be
|
||||
* `abi.encodeWithSignature("Error(string)", "CallWithGas: returnData too long")`
|
||||
*/
|
||||
function functionStaticCallWithGas(
|
||||
address target,
|
||||
bytes memory data,
|
||||
uint256 callGas,
|
||||
uint256 maxReturnBytes
|
||||
) internal view returns (bool success, bytes memory returnData) {
|
||||
assembly ("memory-safe") {
|
||||
returnData := mload(0x40)
|
||||
success := staticcall(callGas, target, add(data, 0x20), mload(data), add(returnData, 0x20), maxReturnBytes)
|
||||
|
||||
// As of the time this contract was written, `verbatim` doesn't work in
|
||||
// inline assembly. Assignment of a value to a variable costs gas
|
||||
// (although how much is unpredictable because it depends on the Yul/IR
|
||||
// optimizer), as does the `GAS` opcode itself. Also solc tends to reorder
|
||||
// the call to `gas()` with preparing the arguments for `div`. Therefore,
|
||||
// the `gas()` below returns less than the actual amount of gas available
|
||||
// for computation at the end of the call. That makes this check slightly
|
||||
// too conservative. However, we do not correct for this because the
|
||||
// correction would become outdated (possibly too permissive) if the
|
||||
// opcodes are repriced.
|
||||
|
||||
// https://eips.ethereum.org/EIPS/eip-150
|
||||
// https://ronan.eth.link/blog/ethereum-gas-dangers/
|
||||
if iszero(or(success, or(returndatasize(), lt(div(callGas, 63), gas())))) {
|
||||
// The call failed due to not enough gas left. We deliberately consume
|
||||
// all remaining gas with `invalid` (instead of `revert`) to make this
|
||||
// failure distinguishable to our caller.
|
||||
invalid()
|
||||
}
|
||||
|
||||
switch gt(returndatasize(), maxReturnBytes)
|
||||
case 0 {
|
||||
switch returndatasize()
|
||||
case 0 {
|
||||
returnData := 0x60
|
||||
success := and(success, iszero(iszero(extcodesize(target))))
|
||||
}
|
||||
default {
|
||||
mstore(returnData, returndatasize())
|
||||
mstore(0x40, add(returnData, add(0x20, returndatasize())))
|
||||
}
|
||||
}
|
||||
default {
|
||||
// returnData = abi.encodeWithSignature("Error(string)", "CallWithGas: returnData too long")
|
||||
success := 0
|
||||
mstore(returnData, 0) // clear potentially dirty bits
|
||||
mstore(add(returnData, 0x04), 0x6408c379a0) // length and selector
|
||||
mstore(add(returnData, 0x24), 0x20)
|
||||
mstore(add(returnData, 0x44), 0x20)
|
||||
mstore(add(returnData, 0x64), "CallWithGas: returnData too long")
|
||||
mstore(0x40, add(returnData, 0x84))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See `functionCallWithGasAndValue`
|
||||
function functionCallWithGas(
|
||||
address target,
|
||||
bytes memory data,
|
||||
uint256 callGas,
|
||||
uint256 maxReturnBytes
|
||||
) internal returns (bool success, bytes memory returnData) {
|
||||
return functionCallWithGasAndValue(payable(target), data, callGas, 0, maxReturnBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice `call` another contract forwarding a precomputed amount of gas.
|
||||
* @notice Unlike `functionStaticCallWithGas`, a failure is not signaled if
|
||||
* there is too much return data. Instead, it is simply truncated.
|
||||
* @dev contains protections against EIP-150-induced insufficient gas griefing
|
||||
* @dev reverts iff caller doesn't have enough native asset balance, the
|
||||
* target is not a contract, or due to out-of-gas
|
||||
* @return success true iff the call succeded
|
||||
* @return returnData the return data or revert reason of the call
|
||||
* @param target the contract (reverts if non-contract) on which to make the
|
||||
* `call`
|
||||
* @param data the calldata to pass
|
||||
* @param callGas the gas to pass for the call. If the call requires more than
|
||||
* the specified amount of gas and the caller didn't provide at
|
||||
* least `callGas`, triggers an out-of-gas in the caller.
|
||||
* @param value the amount of the native asset in wei to pass to the callee
|
||||
* with the call
|
||||
* @param maxReturnBytes Only this many bytes of return data/revert reason are
|
||||
* read back from the call. This prevents griefing the
|
||||
* caller. If more bytes are returned or the revert
|
||||
* reason is longer, returnData will be truncated
|
||||
*/
|
||||
function functionCallWithGasAndValue(
|
||||
address payable target,
|
||||
bytes memory data,
|
||||
uint256 callGas,
|
||||
uint256 value,
|
||||
uint256 maxReturnBytes
|
||||
) internal returns (bool success, bytes memory returnData) {
|
||||
if (value > 0 && (address(this).balance < value || target.code.length == 0)) {
|
||||
return (success, returnData);
|
||||
}
|
||||
|
||||
assembly ("memory-safe") {
|
||||
returnData := mload(0x40)
|
||||
success := call(callGas, target, value, add(data, 0x20), mload(data), add(returnData, 0x20), maxReturnBytes)
|
||||
|
||||
// As of the time this contract was written, `verbatim` doesn't work in
|
||||
// inline assembly. Assignment of a value to a variable costs gas
|
||||
// (although how much is unpredictable because it depends on the Yul/IR
|
||||
// optimizer), as does the `GAS` opcode itself. Also solc tends to reorder
|
||||
// the call to `gas()` with preparing the arguments for `div`. Therefore,
|
||||
// the `gas()` below returns less than the actual amount of gas available
|
||||
// for computation at the end of the call. That makes this check slightly
|
||||
// too conservative. However, we do not correct for this because the
|
||||
// correction would become outdated (possibly too permissive) if the
|
||||
// opcodes are repriced.
|
||||
|
||||
// https://eips.ethereum.org/EIPS/eip-150
|
||||
// https://ronan.eth.link/blog/ethereum-gas-dangers/
|
||||
if iszero(or(success, or(returndatasize(), lt(div(callGas, 63), gas())))) {
|
||||
// The call failed due to not enough gas left. We deliberately consume
|
||||
// all remaining gas with `invalid` (instead of `revert`) to make this
|
||||
// failure distinguishable to our caller.
|
||||
invalid()
|
||||
}
|
||||
|
||||
switch gt(returndatasize(), maxReturnBytes)
|
||||
case 0 {
|
||||
switch returndatasize()
|
||||
case 0 {
|
||||
returnData := 0x60
|
||||
if iszero(value) {
|
||||
success := and(success, iszero(iszero(extcodesize(target))))
|
||||
}
|
||||
}
|
||||
default {
|
||||
mstore(returnData, returndatasize())
|
||||
mstore(0x40, add(returnData, add(0x20, returndatasize())))
|
||||
}
|
||||
}
|
||||
default {
|
||||
mstore(returnData, maxReturnBytes)
|
||||
mstore(0x40, add(returnData, add(0x20, maxReturnBytes)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
contracts/governance/src/IZeroExGovernor.sol
Normal file
39
contracts/governance/src/IZeroExGovernor.sol
Normal file
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "./SecurityCouncil.sol";
|
||||
import "@openzeppelin/governance/IGovernor.sol";
|
||||
import "@openzeppelin/governance/extensions/IGovernorTimelock.sol";
|
||||
|
||||
abstract contract IZeroExGovernor is SecurityCouncil, IGovernor, IGovernorTimelock {
|
||||
function token() public virtual returns (address);
|
||||
|
||||
function proposalThreshold() public view virtual returns (uint256);
|
||||
|
||||
function setVotingDelay(uint256 newVotingDelay) public virtual;
|
||||
|
||||
function setVotingPeriod(uint256 newVotingPeriod) public virtual;
|
||||
|
||||
function setProposalThreshold(uint256 newProposalThreshold) public virtual;
|
||||
|
||||
function proposalVotes(
|
||||
uint256 proposalId
|
||||
) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes);
|
||||
}
|
132
contracts/governance/src/IZeroExVotes.sol
Normal file
132
contracts/governance/src/IZeroExVotes.sol
Normal file
@@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
interface IZeroExVotes {
|
||||
struct Checkpoint {
|
||||
uint32 fromBlock;
|
||||
uint96 votes;
|
||||
uint96 quadraticVotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Emitted when a token transfer or delegate change,
|
||||
* results in changes to a delegate's quadratic number of votes.
|
||||
*/
|
||||
event DelegateQuadraticVotesChanged(
|
||||
address indexed delegate,
|
||||
uint256 previousQuadraticBalance,
|
||||
uint256 newQuadraticBalance
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a token transfer or delegate change, results in changes to a delegate's number of votes.
|
||||
*/
|
||||
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the total supply of the token is changed due to minting and burning which results in
|
||||
* the total supply checkpoint being writtenor updated.
|
||||
*/
|
||||
event TotalSupplyChanged(uint256 totalSupplyVotes, uint256 totalSupplyQuadraticVotes);
|
||||
|
||||
/**
|
||||
* @dev Get the `pos`-th checkpoint for `account`.
|
||||
*/
|
||||
function checkpoints(address account, uint32 pos) external view returns (Checkpoint memory);
|
||||
|
||||
/**
|
||||
* @dev Get number of checkpoints for `account`.
|
||||
*/
|
||||
function numCheckpoints(address account) external view returns (uint32);
|
||||
|
||||
/**
|
||||
* @dev Gets the current votes balance for `account`
|
||||
*/
|
||||
function getVotes(address account) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Gets the current quadratic votes balance for `account`
|
||||
*/
|
||||
function getQuadraticVotes(address account) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `blockNumber` must have been already mined
|
||||
*/
|
||||
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Retrieve the number of quadratic votes for `account` at the end of `blockNumber`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `blockNumber` must have been already mined
|
||||
*/
|
||||
function getPastQuadraticVotes(address account, uint256 blockNumber) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
|
||||
* It is but NOT the sum of all the delegated votes!
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `blockNumber` must have been already mined
|
||||
*/
|
||||
function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Retrieve the sqrt of `totalSupply` at the end of `blockNumber`. Note, this value is the square root of the
|
||||
* sum of all balances.
|
||||
* It is but NOT the sum of all the sqrt of the delegated votes!
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `blockNumber` must have been already mined
|
||||
*/
|
||||
function getPastQuadraticTotalSupply(uint256 blockNumber) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Moves the voting power corresponding to `amount` number of tokens from `src` to `dst`.
|
||||
* Note that if the delegator isn't delegating to anyone before the function call `src` = address(0)
|
||||
* @param src the delegatee we are moving voting power away from
|
||||
* @param dst the delegatee we are moving voting power to
|
||||
* @param srcBalance balance of the delegator whose delegatee is `src`. This is value _after_ the transfer.
|
||||
* @param dstBalance balance of the delegator whose delegatee is `dst`. This is value _after_ the transfer.
|
||||
* @param srcBalanceLastUpdated block number when balance of `src` was last updated.
|
||||
* @param dstBalanceLastUpdated block number when balance of `dst` was last updated.
|
||||
* @param amount The amount of tokens transferred from the source delegate to destination delegate.
|
||||
*/
|
||||
function moveVotingPower(
|
||||
address src,
|
||||
address dst,
|
||||
uint256 srcBalance,
|
||||
uint256 dstBalance,
|
||||
uint96 srcBalanceLastUpdated,
|
||||
uint96 dstBalanceLastUpdated,
|
||||
uint256 amount
|
||||
) external returns (bool);
|
||||
|
||||
function writeCheckpointTotalSupplyMint(uint256 accountBalance, uint256 amount) external returns (bool);
|
||||
|
||||
function writeCheckpointTotalSupplyBurn(uint256 accountBalance, uint256 amount) external returns (bool);
|
||||
}
|
85
contracts/governance/src/SecurityCouncil.sol
Normal file
85
contracts/governance/src/SecurityCouncil.sol
Normal file
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
abstract contract SecurityCouncil {
|
||||
address public securityCouncil;
|
||||
|
||||
event SecurityCouncilAssigned(address securityCouncil);
|
||||
|
||||
event SecurityCouncilEjected();
|
||||
|
||||
modifier onlySecurityCouncil() {
|
||||
_checkSenderIsSecurityCouncil();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks that either a security council is assigned or the payloads array is a council assignment call.
|
||||
*/
|
||||
modifier securityCouncilAssigned(bytes[] memory payloads) {
|
||||
if (securityCouncil == address(0) && !_payloadIsAssignSecurityCouncil(payloads)) {
|
||||
revert("SecurityCouncil: security council not assigned and this is not an assignment call");
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Assigns new security council.
|
||||
*/
|
||||
function assignSecurityCouncil(address _securityCouncil) public virtual {
|
||||
securityCouncil = _securityCouncil;
|
||||
|
||||
emit SecurityCouncilAssigned(securityCouncil);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Ejects the current security council via setting the security council address to 0.
|
||||
* Security council is ejected after they either cancel a proposal or execute a protocol rollback.
|
||||
*/
|
||||
function ejectSecurityCouncil() internal {
|
||||
securityCouncil = address(0);
|
||||
emit SecurityCouncilEjected();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Cancel existing proposal with the submitted `targets`, `values`, `calldatas` and `descriptionHash`.
|
||||
*/
|
||||
function cancel(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) public virtual;
|
||||
|
||||
function _payloadIsAssignSecurityCouncil(bytes[] memory payloads) private pure returns (bool) {
|
||||
require(payloads.length == 1, "SecurityCouncil: more than 1 transaction in proposal");
|
||||
bytes memory payload = payloads[0];
|
||||
// Check this is as assignSecurityCouncil(address) transaction
|
||||
// function signature for assignSecurityCouncil(address)
|
||||
// = bytes4(keccak256("assignSecurityCouncil(address)"))
|
||||
// = 0x2761c3cd
|
||||
if (bytes4(payload) == bytes4(0x2761c3cd)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
function _checkSenderIsSecurityCouncil() private view {
|
||||
require(msg.sender == securityCouncil, "SecurityCouncil: only security council allowed");
|
||||
}
|
||||
}
|
164
contracts/governance/src/ZRXWrappedToken.sol
Normal file
164
contracts/governance/src/ZRXWrappedToken.sol
Normal file
@@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "@openzeppelin/token/ERC20/ERC20.sol";
|
||||
import "@openzeppelin/token/ERC20/extensions/draft-ERC20Permit.sol";
|
||||
import "@openzeppelin/token/ERC20/extensions/ERC20Wrapper.sol";
|
||||
import "@openzeppelin/governance/utils/IVotes.sol";
|
||||
import "@openzeppelin/utils/math/SafeCast.sol";
|
||||
import "./IZeroExVotes.sol";
|
||||
import "./CallWithGas.sol";
|
||||
|
||||
contract ZRXWrappedToken is ERC20, ERC20Permit, ERC20Wrapper {
|
||||
using CallWithGas for address;
|
||||
|
||||
struct DelegateInfo {
|
||||
address delegate;
|
||||
uint96 balanceLastUpdated;
|
||||
}
|
||||
|
||||
constructor(
|
||||
IERC20 wrappedToken,
|
||||
IZeroExVotes _zeroExVotes
|
||||
) ERC20("Wrapped ZRX", "wZRX") ERC20Permit("Wrapped ZRX") ERC20Wrapper(wrappedToken) {
|
||||
zeroExVotes = _zeroExVotes;
|
||||
}
|
||||
|
||||
IZeroExVotes public immutable zeroExVotes;
|
||||
mapping(address => DelegateInfo) private _delegates;
|
||||
|
||||
bytes32 private constant _DELEGATION_TYPEHASH =
|
||||
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
|
||||
|
||||
/**
|
||||
* @dev Emitted when an account changes their delegate.
|
||||
*/
|
||||
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
|
||||
|
||||
// The functions below are the required overrides from the base contracts
|
||||
|
||||
function decimals() public pure override(ERC20, ERC20Wrapper) returns (uint8) {
|
||||
return 18;
|
||||
}
|
||||
|
||||
function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20) {
|
||||
super._afterTokenTransfer(from, to, amount);
|
||||
|
||||
DelegateInfo memory fromDelegate = delegateInfo(from);
|
||||
DelegateInfo memory toDelegate = delegateInfo(to);
|
||||
|
||||
uint256 fromBalance = fromDelegate.delegate == address(0) ? 0 : balanceOf(from) + amount;
|
||||
uint256 toBalance = toDelegate.delegate == address(0) ? 0 : balanceOf(to) - amount;
|
||||
|
||||
if (fromDelegate.delegate != address(0)) _delegates[from].balanceLastUpdated = SafeCast.toUint96(block.number);
|
||||
|
||||
if (toDelegate.delegate != address(0)) _delegates[to].balanceLastUpdated = SafeCast.toUint96(block.number);
|
||||
|
||||
zeroExVotes.moveVotingPower(
|
||||
fromDelegate.delegate,
|
||||
toDelegate.delegate,
|
||||
fromBalance,
|
||||
toBalance,
|
||||
fromDelegate.balanceLastUpdated,
|
||||
toDelegate.balanceLastUpdated,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function _mint(address account, uint256 amount) internal override(ERC20) {
|
||||
super._mint(account, amount);
|
||||
|
||||
zeroExVotes.writeCheckpointTotalSupplyMint(balanceOf(account) - amount, amount);
|
||||
}
|
||||
|
||||
function _burn(address account, uint256 amount) internal override(ERC20) {
|
||||
super._burn(account, amount);
|
||||
|
||||
address(zeroExVotes).functionCallWithGas(
|
||||
abi.encodeCall(zeroExVotes.writeCheckpointTotalSupplyBurn, (balanceOf(account) + amount, amount)),
|
||||
500_000,
|
||||
32
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the address `account` is currently delegating to.
|
||||
*/
|
||||
function delegates(address account) public view returns (address) {
|
||||
return _delegates[account].delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the last block number when `account`'s balance changed.
|
||||
*/
|
||||
function delegatorBalanceLastUpdated(address account) public view returns (uint96) {
|
||||
return _delegates[account].balanceLastUpdated;
|
||||
}
|
||||
|
||||
function delegateInfo(address account) public view returns (DelegateInfo memory) {
|
||||
return _delegates[account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Delegate votes from the sender to `delegatee`.
|
||||
*/
|
||||
function delegate(address delegatee) public {
|
||||
_delegate(_msgSender(), delegatee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Delegates votes from signer to `delegatee`
|
||||
*/
|
||||
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) public {
|
||||
require(block.timestamp <= expiry, "ERC20Votes: signature expired");
|
||||
address signer = ECDSA.recover(
|
||||
_hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
|
||||
_delegate(signer, delegatee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Change delegation for `delegator` to `delegatee`.
|
||||
*
|
||||
* Emits events {DelegateChanged} and {IZeroExVotes-DelegateVotesChanged}.
|
||||
*/
|
||||
function _delegate(address delegator, address delegatee) internal virtual {
|
||||
DelegateInfo memory delegateInfo = delegateInfo(delegator);
|
||||
uint256 delegatorBalance = balanceOf(delegator);
|
||||
|
||||
_delegates[delegator] = DelegateInfo(delegatee, SafeCast.toUint96(block.timestamp));
|
||||
|
||||
emit DelegateChanged(delegator, delegateInfo.delegate, delegatee);
|
||||
|
||||
zeroExVotes.moveVotingPower(
|
||||
delegateInfo.delegate,
|
||||
delegatee,
|
||||
delegatorBalance,
|
||||
0,
|
||||
delegateInfo.balanceLastUpdated,
|
||||
0,
|
||||
delegatorBalance
|
||||
);
|
||||
}
|
||||
}
|
145
contracts/governance/src/ZeroExProtocolGovernor.sol
Normal file
145
contracts/governance/src/ZeroExProtocolGovernor.sol
Normal file
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "./SecurityCouncil.sol";
|
||||
import "./ZeroExTimelock.sol";
|
||||
import "@openzeppelin/governance/Governor.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorSettings.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorCountingSimple.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorVotes.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";
|
||||
|
||||
contract ZeroExProtocolGovernor is
|
||||
SecurityCouncil,
|
||||
Governor,
|
||||
GovernorSettings,
|
||||
GovernorCountingSimple,
|
||||
GovernorVotes,
|
||||
GovernorTimelockControl
|
||||
{
|
||||
constructor(
|
||||
IVotes _votes,
|
||||
ZeroExTimelock _timelock,
|
||||
address _securityCouncil
|
||||
)
|
||||
Governor("ZeroExProtocolGovernor")
|
||||
GovernorSettings(14400 /* 2 days */, 50400 /* 7 days */, 1000000e18)
|
||||
GovernorVotes(_votes)
|
||||
GovernorTimelockControl(TimelockController(payable(_timelock)))
|
||||
{
|
||||
securityCouncil = _securityCouncil;
|
||||
}
|
||||
|
||||
function quorum(uint256 blockNumber) public pure override returns (uint256) {
|
||||
return 10000000e18;
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity.
|
||||
|
||||
function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {
|
||||
return super.votingDelay();
|
||||
}
|
||||
|
||||
function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {
|
||||
return super.votingPeriod();
|
||||
}
|
||||
|
||||
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
|
||||
return super.state(proposalId);
|
||||
}
|
||||
|
||||
function propose(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
string memory description
|
||||
) public override(Governor, IGovernor) securityCouncilAssigned(calldatas) returns (uint256) {
|
||||
return super.propose(targets, values, calldatas, description);
|
||||
}
|
||||
|
||||
function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
|
||||
return super.proposalThreshold();
|
||||
}
|
||||
|
||||
function cancel(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) public override onlySecurityCouncil {
|
||||
_cancel(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
// Like the GovernorTimelockControl.queue function but without the proposal checks,
|
||||
// (as there's effectively no proposal).
|
||||
// And also using a delay of 0 as opposed to the minimum delay of the timelock
|
||||
function executeRollback(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) public onlySecurityCouncil {
|
||||
// Execute the batch of rollbacks via the timelock controller
|
||||
ZeroExTimelock timelockController = ZeroExTimelock(payable(timelock()));
|
||||
timelockController.executeRollbackBatch(targets, values, calldatas, 0, descriptionHash);
|
||||
}
|
||||
|
||||
function assignSecurityCouncil(address _securityCouncil) public override onlyGovernance {
|
||||
super.assignSecurityCouncil(_securityCouncil);
|
||||
}
|
||||
|
||||
function queue(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) public override securityCouncilAssigned(calldatas) returns (uint256) {
|
||||
return super.queue(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _execute(
|
||||
uint256 proposalId,
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) {
|
||||
super._execute(proposalId, targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _cancel(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
|
||||
return super._cancel(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
|
||||
return super._executor();
|
||||
}
|
||||
|
||||
function supportsInterface(
|
||||
bytes4 interfaceId
|
||||
) public view override(Governor, GovernorTimelockControl) returns (bool) {
|
||||
return super.supportsInterface(interfaceId);
|
||||
}
|
||||
}
|
70
contracts/governance/src/ZeroExTimelock.sol
Normal file
70
contracts/governance/src/ZeroExTimelock.sol
Normal file
@@ -0,0 +1,70 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "@openzeppelin/governance/TimelockController.sol";
|
||||
|
||||
contract ZeroExTimelock is TimelockController {
|
||||
// minDelay is how long you have to wait before executing
|
||||
// proposers is the list of addresses that can propose
|
||||
// executors is the list of addresses that can execute
|
||||
constructor(
|
||||
uint256 minDelay,
|
||||
address[] memory proposers,
|
||||
address[] memory executors,
|
||||
address admin
|
||||
) TimelockController(minDelay, proposers, executors, admin) {}
|
||||
|
||||
/**
|
||||
* @dev Execute a batch of rollback transactions. Similar to TimelockController.executeBatch function but without
|
||||
* the timelock checks.
|
||||
* Emits one {CallExecuted} event per transaction in the batch.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the caller must have the 'executor' role.
|
||||
*/
|
||||
function executeRollbackBatch(
|
||||
address[] calldata targets,
|
||||
uint256[] calldata values,
|
||||
bytes[] calldata payloads,
|
||||
bytes32 predecessor,
|
||||
bytes32 salt
|
||||
) public payable onlyRoleOrOpenRole(EXECUTOR_ROLE) {
|
||||
require(targets.length > 0, "ZeroExTimelock: empty targets");
|
||||
require(targets.length == values.length, "ZeroExTimelock: length mismatch");
|
||||
require(targets.length == payloads.length, "ZeroExTimelock: length mismatch");
|
||||
|
||||
bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);
|
||||
|
||||
for (uint256 i = 0; i < targets.length; ++i) {
|
||||
address target = targets[i];
|
||||
uint256 value = values[i];
|
||||
bytes calldata payload = payloads[i];
|
||||
// Check this is a rollback transaction
|
||||
// function signature for rollback(bytes4,address)
|
||||
// = bytes4(keccak256("rollback(bytes4,address)"))
|
||||
// = 0x9db64a40
|
||||
require(bytes4(payload) == bytes4(0x9db64a40), "ZeroExTimelock: not rollback");
|
||||
|
||||
_execute(target, value, payload);
|
||||
emit CallExecuted(id, i, target, value, payload);
|
||||
}
|
||||
}
|
||||
}
|
154
contracts/governance/src/ZeroExTreasuryGovernor.sol
Normal file
154
contracts/governance/src/ZeroExTreasuryGovernor.sol
Normal file
@@ -0,0 +1,154 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "@openzeppelin/governance/Governor.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorSettings.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorCountingSimple.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorVotes.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorVotesQuorumFraction.sol";
|
||||
import "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";
|
||||
|
||||
import "./IZeroExVotes.sol";
|
||||
import "./SecurityCouncil.sol";
|
||||
|
||||
contract ZeroExTreasuryGovernor is
|
||||
SecurityCouncil,
|
||||
Governor,
|
||||
GovernorSettings,
|
||||
GovernorCountingSimple,
|
||||
GovernorVotes,
|
||||
GovernorVotesQuorumFraction,
|
||||
GovernorTimelockControl
|
||||
{
|
||||
constructor(
|
||||
IVotes votes,
|
||||
TimelockController _timelock,
|
||||
address _securityCouncil
|
||||
)
|
||||
Governor("ZeroExTreasuryGovernor")
|
||||
GovernorSettings(14400 /* 2 days */, 50400 /* 7 days */, 250000e18)
|
||||
GovernorVotes(votes)
|
||||
GovernorVotesQuorumFraction(10)
|
||||
GovernorTimelockControl(_timelock)
|
||||
{
|
||||
securityCouncil = _securityCouncil;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the "quadratic" quorum for a block number, in terms of number of votes:
|
||||
* `quadratic total supply * numerator / denominator`
|
||||
*/
|
||||
function quorum(
|
||||
uint256 blockNumber
|
||||
) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) {
|
||||
IZeroExVotes votes = IZeroExVotes(address(token));
|
||||
return (votes.getPastQuadraticTotalSupply(blockNumber) * quorumNumerator(blockNumber)) / quorumDenominator();
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity.
|
||||
|
||||
function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {
|
||||
return super.votingDelay();
|
||||
}
|
||||
|
||||
function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {
|
||||
return super.votingPeriod();
|
||||
}
|
||||
|
||||
function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
|
||||
return super.proposalThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten GovernorVotes implementation
|
||||
* Read the quadratic voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}).
|
||||
*/
|
||||
function _getVotes(
|
||||
address account,
|
||||
uint256 blockNumber,
|
||||
bytes memory /*params*/
|
||||
) internal view virtual override(Governor, GovernorVotes) returns (uint256) {
|
||||
return IZeroExVotes(address(token)).getPastQuadraticVotes(account, blockNumber);
|
||||
}
|
||||
|
||||
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
|
||||
return super.state(proposalId);
|
||||
}
|
||||
|
||||
function propose(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
string memory description
|
||||
) public override(Governor, IGovernor) securityCouncilAssigned(calldatas) returns (uint256) {
|
||||
return super.propose(targets, values, calldatas, description);
|
||||
}
|
||||
|
||||
function cancel(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) public override onlySecurityCouncil {
|
||||
_cancel(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function assignSecurityCouncil(address _securityCouncil) public override onlyGovernance {
|
||||
super.assignSecurityCouncil(_securityCouncil);
|
||||
}
|
||||
|
||||
function queue(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) public override securityCouncilAssigned(calldatas) returns (uint256) {
|
||||
return super.queue(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _execute(
|
||||
uint256 proposalId,
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) {
|
||||
super._execute(proposalId, targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _cancel(
|
||||
address[] memory targets,
|
||||
uint256[] memory values,
|
||||
bytes[] memory calldatas,
|
||||
bytes32 descriptionHash
|
||||
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
|
||||
return super._cancel(targets, values, calldatas, descriptionHash);
|
||||
}
|
||||
|
||||
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
|
||||
return super._executor();
|
||||
}
|
||||
|
||||
function supportsInterface(
|
||||
bytes4 interfaceId
|
||||
) public view override(Governor, GovernorTimelockControl) returns (bool) {
|
||||
return super.supportsInterface(interfaceId);
|
||||
}
|
||||
}
|
336
contracts/governance/src/ZeroExVotes.sol
Normal file
336
contracts/governance/src/ZeroExVotes.sol
Normal file
@@ -0,0 +1,336 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "@openzeppelin/utils/math/SafeCast.sol";
|
||||
import "@openzeppelin/utils/math/Math.sol";
|
||||
import "@openzeppelin/token/ERC20/ERC20.sol";
|
||||
import "@openzeppelin/governance/utils/IVotes.sol";
|
||||
import "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||
import "@openzeppelin-contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
import "./IZeroExVotes.sol";
|
||||
|
||||
contract ZeroExVotes is IZeroExVotes, Initializable, OwnableUpgradeable, UUPSUpgradeable {
|
||||
address public immutable token;
|
||||
uint256 public immutable quadraticThreshold;
|
||||
|
||||
mapping(address => Checkpoint[]) internal _checkpoints;
|
||||
Checkpoint[] private _totalSupplyCheckpoints;
|
||||
|
||||
constructor(address _token, uint256 _quadraticThreshold) {
|
||||
require(_token != address(0), "ZeroExVotes: token cannot be 0");
|
||||
token = _token;
|
||||
quadraticThreshold = _quadraticThreshold;
|
||||
_disableInitializers();
|
||||
}
|
||||
|
||||
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
|
||||
|
||||
modifier onlyToken() {
|
||||
_checkSenderIsToken();
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize() public virtual onlyProxy initializer {
|
||||
__Ownable_init();
|
||||
__UUPSUpgradeable_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function checkpoints(address account, uint32 pos) public view returns (Checkpoint memory) {
|
||||
return _checkpoints[account][pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function numCheckpoints(address account) public view returns (uint32) {
|
||||
return SafeCast.toUint32(_checkpoints[account].length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function getVotes(address account) public view returns (uint256) {
|
||||
unchecked {
|
||||
uint256 pos = _checkpoints[account].length;
|
||||
return pos == 0 ? 0 : _unsafeAccess(_checkpoints[account], pos - 1).votes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function getQuadraticVotes(address account) public view returns (uint256) {
|
||||
unchecked {
|
||||
uint256 pos = _checkpoints[account].length;
|
||||
return pos == 0 ? 0 : _unsafeAccess(_checkpoints[account], pos - 1).quadraticVotes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) {
|
||||
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
|
||||
|
||||
Checkpoint memory checkpoint = _checkpointsLookup(_checkpoints[account], blockNumber);
|
||||
return checkpoint.votes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function getPastQuadraticVotes(address account, uint256 blockNumber) public view returns (uint256) {
|
||||
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
|
||||
|
||||
Checkpoint memory checkpoint = _checkpointsLookup(_checkpoints[account], blockNumber);
|
||||
return checkpoint.quadraticVotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function getPastTotalSupply(uint256 blockNumber) public view returns (uint256) {
|
||||
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
|
||||
|
||||
// Note that due to the disabled updates of `_totalSupplyCheckpoints` in `writeCheckpointTotalSupply` function
|
||||
// this always returns 0.
|
||||
Checkpoint memory checkpoint = _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
|
||||
return checkpoint.votes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function getPastQuadraticTotalSupply(uint256 blockNumber) public view returns (uint256) {
|
||||
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
|
||||
|
||||
// Note that due to the disabled updates of `_totalSupplyCheckpoints` in `writeCheckpointTotalSupply` function
|
||||
// this always returns 0.
|
||||
Checkpoint memory checkpoint = _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
|
||||
return checkpoint.quadraticVotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function moveVotingPower(
|
||||
address src,
|
||||
address dst,
|
||||
uint256 srcBalance,
|
||||
uint256 dstBalance,
|
||||
uint96 srcBalanceLastUpdated,
|
||||
uint96 dstBalanceLastUpdated,
|
||||
uint256 amount
|
||||
) public virtual onlyToken returns (bool) {
|
||||
if (src != dst) {
|
||||
if (src != address(0)) {
|
||||
(
|
||||
uint256 oldWeight,
|
||||
uint256 newWeight,
|
||||
uint256 oldQuadraticWeight,
|
||||
uint256 newQuadraticWeight
|
||||
) = _writeCheckpoint(_checkpoints[src], _subtract, srcBalance, srcBalanceLastUpdated, amount);
|
||||
|
||||
emit DelegateVotesChanged(src, oldWeight, newWeight);
|
||||
emit DelegateQuadraticVotesChanged(src, oldQuadraticWeight, newQuadraticWeight);
|
||||
}
|
||||
|
||||
if (dst != address(0)) {
|
||||
(
|
||||
uint256 oldWeight,
|
||||
uint256 newWeight,
|
||||
uint256 oldQuadraticWeight,
|
||||
uint256 newQuadraticWeight
|
||||
) = _writeCheckpoint(_checkpoints[dst], _add, dstBalance, dstBalanceLastUpdated, amount);
|
||||
|
||||
emit DelegateVotesChanged(dst, oldWeight, newWeight);
|
||||
emit DelegateQuadraticVotesChanged(dst, oldQuadraticWeight, newQuadraticWeight);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function writeCheckpointTotalSupplyMint(
|
||||
uint256 accountBalance,
|
||||
uint256 amount
|
||||
) public virtual onlyToken returns (bool) {
|
||||
(, uint256 newWeight, , uint256 newQuadraticWeight) = _writeCheckpoint(
|
||||
_totalSupplyCheckpoints,
|
||||
_add,
|
||||
accountBalance,
|
||||
0,
|
||||
amount
|
||||
);
|
||||
|
||||
emit TotalSupplyChanged(newWeight, newQuadraticWeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc IZeroExVotes
|
||||
*/
|
||||
function writeCheckpointTotalSupplyBurn(
|
||||
uint256 accountBalance,
|
||||
uint256 amount
|
||||
) public virtual onlyToken returns (bool) {
|
||||
(, uint256 newWeight, , uint256 newQuadraticWeight) = _writeCheckpoint(
|
||||
_totalSupplyCheckpoints,
|
||||
_subtract,
|
||||
accountBalance,
|
||||
0,
|
||||
amount
|
||||
);
|
||||
|
||||
emit TotalSupplyChanged(newWeight, newQuadraticWeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Lookup a value in a list of (sorted) checkpoints.
|
||||
* Implementation as in openzeppelin/token/ERC20/extensions/ERC20Votes.sol except here we return the entire
|
||||
* checkpoint rather than part of it
|
||||
*/
|
||||
function _checkpointsLookup(
|
||||
Checkpoint[] storage ckpts,
|
||||
uint256 blockNumber
|
||||
) internal view returns (Checkpoint memory checkpoint) {
|
||||
// We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
|
||||
//
|
||||
// Initially we check if the block is recent to narrow the search range.
|
||||
// During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
|
||||
// With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the
|
||||
// invariant.
|
||||
// - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
|
||||
// - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
|
||||
// Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
|
||||
// out of bounds (in which case we're looking too far in the past and the result is 0).
|
||||
// Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
|
||||
// past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
|
||||
// the same.
|
||||
uint256 length = ckpts.length;
|
||||
|
||||
uint256 low = 0;
|
||||
uint256 high = length;
|
||||
|
||||
if (length > 5) {
|
||||
uint256 mid = length - Math.sqrt(length);
|
||||
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Leaving here for posterity this is the original OZ implementation which we've replaced
|
||||
// return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
|
||||
if (high != 0) checkpoint = _unsafeAccess(ckpts, high - 1);
|
||||
}
|
||||
|
||||
function _writeCheckpoint(
|
||||
Checkpoint[] storage ckpts,
|
||||
function(uint256, uint256) view returns (uint256) op,
|
||||
uint256 userBalance,
|
||||
uint96 balanceLastUpdated,
|
||||
uint256 delta
|
||||
)
|
||||
internal
|
||||
virtual
|
||||
returns (uint256 oldWeight, uint256 newWeight, uint256 oldQuadraticWeight, uint256 newQuadraticWeight)
|
||||
{
|
||||
uint256 pos = ckpts.length;
|
||||
|
||||
Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0, 0) : _unsafeAccess(ckpts, pos - 1);
|
||||
|
||||
oldWeight = oldCkpt.votes;
|
||||
newWeight = op(oldWeight, delta);
|
||||
|
||||
oldQuadraticWeight = oldCkpt.quadraticVotes;
|
||||
|
||||
// Remove the entire sqrt userBalance from quadratic voting power.
|
||||
// Note that `userBalance` is value _after_ transfer.
|
||||
if (pos > 0) {
|
||||
uint256 oldQuadraticVotingPower = userBalance <= quadraticThreshold
|
||||
? userBalance
|
||||
: quadraticThreshold + Math.sqrt((userBalance - quadraticThreshold) * 1e18);
|
||||
oldCkpt.quadraticVotes -= SafeCast.toUint96(oldQuadraticVotingPower);
|
||||
}
|
||||
|
||||
// if wallet > threshold, calculate quadratic power over the treshold only, below threshold is linear
|
||||
uint256 newBalance = op(userBalance, delta);
|
||||
uint256 newQuadraticBalance = newBalance <= quadraticThreshold
|
||||
? newBalance
|
||||
: quadraticThreshold + Math.sqrt((newBalance - quadraticThreshold) * 1e18);
|
||||
newQuadraticWeight = oldCkpt.quadraticVotes + newQuadraticBalance;
|
||||
|
||||
if (pos > 0 && oldCkpt.fromBlock == block.number) {
|
||||
Checkpoint storage chpt = _unsafeAccess(ckpts, pos - 1);
|
||||
chpt.votes = SafeCast.toUint96(newWeight);
|
||||
chpt.quadraticVotes = SafeCast.toUint96(newQuadraticWeight);
|
||||
} else {
|
||||
ckpts.push(
|
||||
Checkpoint({
|
||||
fromBlock: SafeCast.toUint32(block.number),
|
||||
votes: SafeCast.toUint96(newWeight),
|
||||
quadraticVotes: SafeCast.toUint96(newQuadraticWeight)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function _add(uint256 a, uint256 b) private pure returns (uint256) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
|
||||
* Implementation from openzeppelin/token/ERC20/extensions/ERC20Votes.sol
|
||||
* https://github.com/ethereum/solidity/issues/9117
|
||||
*/
|
||||
function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) internal pure returns (Checkpoint storage result) {
|
||||
assembly ("memory-safe") {
|
||||
mstore(0, ckpts.slot)
|
||||
result.slot := add(keccak256(0, 0x20), pos)
|
||||
}
|
||||
}
|
||||
|
||||
function _checkSenderIsToken() private {
|
||||
require(msg.sender == token, "ZeroExVotes: only token allowed");
|
||||
}
|
||||
}
|
167
contracts/governance/test/BaseTest.t.sol
Normal file
167
contracts/governance/test/BaseTest.t.sol
Normal file
@@ -0,0 +1,167 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "forge-std/console.sol";
|
||||
import "@openzeppelin/token/ERC20/ERC20.sol";
|
||||
import "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
|
||||
import "./mocks/ZRXMock.sol";
|
||||
import "../src/ZRXWrappedToken.sol";
|
||||
import "../src/ZeroExVotes.sol";
|
||||
import "../src/ZeroExTimelock.sol";
|
||||
import "../src/ZeroExProtocolGovernor.sol";
|
||||
import "../src/ZeroExTreasuryGovernor.sol";
|
||||
|
||||
contract BaseTest is Test {
|
||||
address payable internal account1 = payable(vm.addr(1));
|
||||
address payable internal account2 = payable(vm.addr(2));
|
||||
address payable internal account3 = payable(vm.addr(3));
|
||||
address payable internal account4 = payable(vm.addr(4));
|
||||
address payable internal securityCouncil = payable(vm.addr(5));
|
||||
uint256 internal quadraticThreshold = 1000000e18;
|
||||
|
||||
bytes32 internal constant DELEGATION_TYPEHASH =
|
||||
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
|
||||
|
||||
constructor() {
|
||||
vm.deal(account1, 1e20);
|
||||
vm.deal(account2, 1e20);
|
||||
vm.deal(account3, 1e20);
|
||||
vm.deal(account4, 1e20);
|
||||
vm.deal(securityCouncil, 1e20);
|
||||
}
|
||||
|
||||
function setupGovernance(
|
||||
IERC20 zrxToken
|
||||
) internal returns (ZRXWrappedToken, ZeroExVotes, ZeroExTimelock, ZeroExTimelock, address, address) {
|
||||
(ZRXWrappedToken token, ZeroExVotes votes) = setupZRXWrappedToken(zrxToken);
|
||||
|
||||
vm.startPrank(account1);
|
||||
address[] memory proposers = new address[](0);
|
||||
address[] memory executors = new address[](0);
|
||||
|
||||
ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, account1);
|
||||
ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
|
||||
IVotes(address(votes)),
|
||||
protocolTimelock,
|
||||
securityCouncil
|
||||
);
|
||||
protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
|
||||
protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
|
||||
protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
|
||||
|
||||
ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, account1);
|
||||
ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
|
||||
IVotes(address(votes)),
|
||||
treasuryTimelock,
|
||||
securityCouncil
|
||||
);
|
||||
|
||||
treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
|
||||
treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
|
||||
treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
|
||||
vm.stopPrank();
|
||||
|
||||
return (token, votes, protocolTimelock, treasuryTimelock, address(protocolGovernor), address(treasuryGovernor));
|
||||
}
|
||||
|
||||
function setupZRXWrappedToken(IERC20 zrxToken) internal returns (ZRXWrappedToken, ZeroExVotes) {
|
||||
vm.startPrank(account1);
|
||||
address wTokenPrediction = predictAddress(account1, vm.getNonce(account1) + 2);
|
||||
ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, quadraticThreshold);
|
||||
ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
|
||||
ZRXWrappedToken wToken = new ZRXWrappedToken(zrxToken, ZeroExVotes(address(votesProxy)));
|
||||
vm.stopPrank();
|
||||
|
||||
assert(address(wToken) == wTokenPrediction);
|
||||
|
||||
return (wToken, ZeroExVotes(address(votesProxy)));
|
||||
}
|
||||
|
||||
function mockZRXToken() internal returns (IERC20 zrxToken) {
|
||||
vm.startPrank(account1);
|
||||
bytes memory _bytecode = vm.getCode("./ZRXToken.json");
|
||||
assembly {
|
||||
zrxToken := create(0, add(_bytecode, 0x20), mload(_bytecode))
|
||||
}
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
// Sourced from https://github.com/grappafinance/core/blob/master/src/test/utils/Utilities.sol
|
||||
function predictAddress(address _origin, uint256 _nonce) public pure returns (address) {
|
||||
if (_nonce == 0x00) {
|
||||
return
|
||||
address(
|
||||
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80)))))
|
||||
);
|
||||
}
|
||||
if (_nonce <= 0x7f) {
|
||||
return
|
||||
address(
|
||||
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, uint8(_nonce)))))
|
||||
);
|
||||
}
|
||||
if (_nonce <= 0xff) {
|
||||
return
|
||||
address(
|
||||
uint160(
|
||||
uint256(
|
||||
keccak256(
|
||||
abi.encodePacked(bytes1(0xd7), bytes1(0x94), _origin, bytes1(0x81), uint8(_nonce))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (_nonce <= 0xffff) {
|
||||
return
|
||||
address(
|
||||
uint160(
|
||||
uint256(
|
||||
keccak256(
|
||||
abi.encodePacked(bytes1(0xd8), bytes1(0x94), _origin, bytes1(0x82), uint16(_nonce))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (_nonce <= 0xffffff) {
|
||||
return
|
||||
address(
|
||||
uint160(
|
||||
uint256(
|
||||
keccak256(
|
||||
abi.encodePacked(bytes1(0xd9), bytes1(0x94), _origin, bytes1(0x83), uint24(_nonce))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return
|
||||
address(
|
||||
uint160(
|
||||
uint256(
|
||||
keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), _origin, bytes1(0x84), uint32(_nonce)))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
454
contracts/governance/test/integration/GovernanceE2E.t.sol
Normal file
454
contracts/governance/test/integration/GovernanceE2E.t.sol
Normal file
@@ -0,0 +1,454 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "@openzeppelin/token/ERC20/IERC20.sol";
|
||||
import "../mocks/IZeroExMock.sol";
|
||||
import "../mocks/IZrxTreasuryMock.sol";
|
||||
import "../mocks/IStakingMock.sol";
|
||||
import "../mocks/IZrxVaultMock.sol";
|
||||
import "../BaseTest.t.sol";
|
||||
import "../../src/ZRXWrappedToken.sol";
|
||||
import "../../src/ZeroExVotes.sol";
|
||||
import "../../src/ZeroExTimelock.sol";
|
||||
import "../../src/ZeroExProtocolGovernor.sol";
|
||||
import "../../src/ZeroExTreasuryGovernor.sol";
|
||||
|
||||
contract GovernanceE2ETest is BaseTest {
|
||||
uint256 internal mainnetFork;
|
||||
string internal MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
|
||||
|
||||
struct DelegatorPool {
|
||||
address delegator;
|
||||
bytes32 pool;
|
||||
}
|
||||
|
||||
address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
|
||||
address internal constant MATIC_TOKEN = 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0;
|
||||
address internal constant WCELO_TOKEN = 0xE452E6Ea2dDeB012e20dB73bf5d3863A3Ac8d77a;
|
||||
address internal constant WYV_TOKEN = 0x056017c55aE7AE32d12AeF7C679dF83A85ca75Ff;
|
||||
|
||||
address internal constant EXCHANGE_PROXY = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
|
||||
address internal constant EXCHANGE_GOVERNOR = 0x618F9C67CE7Bf1a50afa1E7e0238422601b0ff6e;
|
||||
address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
|
||||
address internal constant STAKING = 0xa26e80e7Dea86279c6d778D702Cc413E6CFfA777; // Holds ~$262K in WETH for rewards
|
||||
address internal constant ZRX_VAULT = 0xBa7f8b5fB1b19c1211c5d49550fcD149177A5Eaf; // Holds ~$10m in staked ZRX
|
||||
address internal constant STAKING_AND_VAULT_OWNER = 0x7D3455421BbC5Ed534a83c88FD80387dc8271392;
|
||||
|
||||
address internal staker1 = 0x885c327cAD2aebb969dfaAb4c928B73CA17e3887;
|
||||
address internal staker2 = 0x03c823e96F6964076C118395F08a2D7edF0f8a8C;
|
||||
|
||||
address[] internal topStakers = [
|
||||
0x5775afA796818ADA27b09FaF5c90d101f04eF600,
|
||||
0xE1bdcd3B70e077D2d66ADcbe78be3941F0BF380B,
|
||||
0xcCa71809E8870AFEB72c4720d0fe50d5C3230e05,
|
||||
0x828FD91d3e3a9FFa6305e78B9aE2Cfbc5B5D9f6B,
|
||||
0x4A36C3DA5d367B148d17265e7d7feafcf8fb4a21,
|
||||
0xEeff6fd32DeaFe1a9d3258A51c7F952F9FF0B2Ce,
|
||||
0x1D0738b927dFCBFBD59A9F0944BbD1860d3B9248,
|
||||
0x0C073E7248C1b548a08b27dD3af5D0f39c774280,
|
||||
0xA178FF321335BB777A7E21A56376592F69556b9c,
|
||||
0xD06CfBb59d2e8918F84D99d981039d7706DCA288
|
||||
];
|
||||
|
||||
// voting power 1500000e18
|
||||
address internal voter1 = 0x292c6DAE7417B3D31d8B6e1d2EeA0258d14C4C4b;
|
||||
bytes32 internal voter1Pool = 0x0000000000000000000000000000000000000000000000000000000000000030;
|
||||
bytes32[] internal voter1_operated_poolIds = [voter1Pool];
|
||||
|
||||
// voting power 1500000.5e18
|
||||
address internal voter2 = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
|
||||
bytes32 internal voter2Pool = 0x0000000000000000000000000000000000000000000000000000000000000031;
|
||||
bytes32[] internal voter2_operated_poolIds = [voter2Pool];
|
||||
|
||||
// voting power 1500000e18
|
||||
address internal voter3 = 0x5265Bde27F57E738bE6c1F6AB3544e82cdc92a8f;
|
||||
bytes32 internal voter3Pool = 0x0000000000000000000000000000000000000000000000000000000000000032;
|
||||
bytes32[] internal voter3_operated_poolIds = [voter3Pool];
|
||||
|
||||
// voting power 1500000e18
|
||||
address internal voter4 = 0xcA9F5049c1Ea8FC78574f94B7Cf5bE5fEE354C31;
|
||||
bytes32 internal voter4Pool = 0x0000000000000000000000000000000000000000000000000000000000000034;
|
||||
bytes32[] internal voter4_operated_poolIds = [voter4Pool];
|
||||
|
||||
// voting power 1500000e18
|
||||
address internal voter5 = 0xDBB5664a9DBCB98F6365804880e5b277B3155422;
|
||||
bytes32 internal voter5Pool = 0x0000000000000000000000000000000000000000000000000000000000000035;
|
||||
bytes32[] internal voter5_operated_poolIds = [voter5Pool];
|
||||
|
||||
// voting power 2291490.952353335e18
|
||||
address internal voter6 = 0x9a4Eb1101C0c053505Bd71d2fFa27Ed902DEaD85;
|
||||
bytes32 internal voter6Pool = 0x0000000000000000000000000000000000000000000000000000000000000029;
|
||||
bytes32[] internal voter6_operated_poolIds = [voter6Pool];
|
||||
|
||||
// voting power 4575984.325e18
|
||||
address internal voter7 = 0x9564177EC8052C92752a488a71769F710aA0A41D;
|
||||
bytes32 internal voter7Pool = 0x0000000000000000000000000000000000000000000000000000000000000025;
|
||||
bytes32[] internal voter7_operated_poolIds = [voter7Pool];
|
||||
|
||||
IERC20 internal token;
|
||||
IERC20 internal maticToken;
|
||||
IERC20 internal wceloToken;
|
||||
IERC20 internal wyvToken;
|
||||
|
||||
IZeroExMock internal exchange;
|
||||
IZrxTreasuryMock internal treasury;
|
||||
IZrxVaultMock internal vault;
|
||||
IStakingMock internal staking;
|
||||
IERC20 internal weth;
|
||||
|
||||
ZRXWrappedToken internal wToken;
|
||||
ZeroExVotes internal votes;
|
||||
ZeroExTimelock internal protocolTimelock;
|
||||
ZeroExTimelock internal treasuryTimelock;
|
||||
ZeroExProtocolGovernor internal protocolGovernor;
|
||||
ZeroExTreasuryGovernor internal treasuryGovernor;
|
||||
|
||||
function setUp() public {
|
||||
mainnetFork = vm.createFork(MAINNET_RPC_URL);
|
||||
vm.selectFork(mainnetFork);
|
||||
|
||||
token = IERC20(ZRX_TOKEN);
|
||||
maticToken = IERC20(MATIC_TOKEN);
|
||||
wceloToken = IERC20(WCELO_TOKEN);
|
||||
wyvToken = IERC20(WYV_TOKEN);
|
||||
|
||||
exchange = IZeroExMock(payable(EXCHANGE_PROXY));
|
||||
treasury = IZrxTreasuryMock(TREASURY);
|
||||
vault = IZrxVaultMock(ZRX_VAULT);
|
||||
staking = IStakingMock(STAKING);
|
||||
weth = IERC20(staking.getWethContract());
|
||||
|
||||
address protocolGovernorAddress;
|
||||
address treasuryGovernorAddress;
|
||||
(
|
||||
wToken,
|
||||
votes,
|
||||
protocolTimelock,
|
||||
treasuryTimelock,
|
||||
protocolGovernorAddress,
|
||||
treasuryGovernorAddress
|
||||
) = setupGovernance(token);
|
||||
|
||||
protocolGovernor = ZeroExProtocolGovernor(payable(protocolGovernorAddress));
|
||||
treasuryGovernor = ZeroExTreasuryGovernor(payable(treasuryGovernorAddress));
|
||||
}
|
||||
|
||||
function testProtocolGovernanceMigration() public {
|
||||
// initially the zrx exchange is owned by the legacy exchange governor
|
||||
assertEq(exchange.owner(), EXCHANGE_GOVERNOR);
|
||||
|
||||
// transfer ownership to new protocol governor
|
||||
vm.prank(EXCHANGE_GOVERNOR);
|
||||
exchange.transferOwnership(address(protocolGovernor));
|
||||
assertEq(exchange.owner(), address(protocolGovernor));
|
||||
}
|
||||
|
||||
function testTreasuryGovernanceMigration() public {
|
||||
// Create a proposal to migrate to new governor
|
||||
|
||||
uint256 currentEpoch = staking.currentEpoch();
|
||||
uint256 executionEpoch = currentEpoch + 2;
|
||||
|
||||
vm.startPrank(voter3);
|
||||
|
||||
IZrxTreasuryMock.ProposedAction[] memory actions = new IZrxTreasuryMock.ProposedAction[](4);
|
||||
|
||||
// Transfer MATIC
|
||||
uint256 maticBalance = maticToken.balanceOf(address(treasury));
|
||||
actions[0] = IZrxTreasuryMock.ProposedAction({
|
||||
target: MATIC_TOKEN,
|
||||
data: abi.encodeCall(maticToken.transfer, (address(treasuryGovernor), maticBalance)),
|
||||
value: 0
|
||||
});
|
||||
|
||||
// Transfer ZRX
|
||||
uint256 zrxBalance = token.balanceOf(address(treasury));
|
||||
actions[1] = IZrxTreasuryMock.ProposedAction({
|
||||
target: ZRX_TOKEN,
|
||||
data: abi.encodeCall(token.transfer, (address(treasuryGovernor), zrxBalance)),
|
||||
value: 0
|
||||
});
|
||||
|
||||
// Transfer wCELO
|
||||
uint256 wceloBalance = wceloToken.balanceOf(address(treasury));
|
||||
actions[2] = IZrxTreasuryMock.ProposedAction({
|
||||
target: WCELO_TOKEN,
|
||||
data: abi.encodeCall(wceloToken.transfer, (address(treasuryGovernor), wceloBalance)),
|
||||
value: 0
|
||||
});
|
||||
|
||||
// Transfer WYV
|
||||
uint256 wyvBalance = wyvToken.balanceOf(address(treasury));
|
||||
actions[3] = IZrxTreasuryMock.ProposedAction({
|
||||
target: WYV_TOKEN,
|
||||
data: abi.encodeCall(wyvToken.transfer, (address(treasuryGovernor), wyvBalance)),
|
||||
value: 0
|
||||
});
|
||||
|
||||
uint256 proposalId = treasury.propose(
|
||||
actions,
|
||||
executionEpoch,
|
||||
"Z-5 Migrate to new treasury governor",
|
||||
voter3_operated_poolIds
|
||||
);
|
||||
|
||||
// Once a proposal is created, it becomes open for voting at the epoch after next (currentEpoch + 2)
|
||||
// and is open for the voting period (currently set to 3 days).
|
||||
uint256 epochDurationInSeconds = staking.epochDurationInSeconds(); // Currently set to 604800 seconds = 7 days
|
||||
uint256 currentEpochEndTime = staking.currentEpochStartTimeInSeconds() + epochDurationInSeconds;
|
||||
|
||||
vm.warp(currentEpochEndTime + 1);
|
||||
staking.endEpoch();
|
||||
vm.warp(block.timestamp + epochDurationInSeconds + 1);
|
||||
staking.endEpoch();
|
||||
|
||||
vm.stopPrank();
|
||||
// quorum is 10,000,000e18 so reach that via the following votes
|
||||
vm.prank(voter1);
|
||||
treasury.castVote(proposalId, true, voter1_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.prank(voter2);
|
||||
treasury.castVote(proposalId, true, voter2_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.prank(voter3);
|
||||
treasury.castVote(proposalId, true, voter3_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.prank(voter4);
|
||||
treasury.castVote(proposalId, true, voter4_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.prank(voter5);
|
||||
treasury.castVote(proposalId, true, voter5_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.prank(voter6);
|
||||
treasury.castVote(proposalId, true, voter6_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.prank(voter7);
|
||||
treasury.castVote(proposalId, true, voter7_operated_poolIds);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.warp(block.timestamp + 3 days + 1);
|
||||
|
||||
// Execute proposal
|
||||
treasury.execute(proposalId, actions);
|
||||
|
||||
// Assert value of treasury has correctly transferred
|
||||
uint256 maticBalanceNewTreasury = maticToken.balanceOf(address(treasuryGovernor));
|
||||
assertEq(maticBalanceNewTreasury, maticBalance);
|
||||
|
||||
uint256 zrxBalanceNewTreasury = token.balanceOf(address(treasuryGovernor));
|
||||
assertEq(zrxBalanceNewTreasury, zrxBalance);
|
||||
|
||||
uint256 wceloBalanceNewTreasury = wceloToken.balanceOf(address(treasuryGovernor));
|
||||
assertEq(wceloBalanceNewTreasury, wceloBalance);
|
||||
|
||||
uint256 wyvBalanceNewTreasury = wyvToken.balanceOf(address(treasuryGovernor));
|
||||
assertEq(wyvBalanceNewTreasury, wyvBalance);
|
||||
}
|
||||
|
||||
// Test entering catastrophic failure mode on the zrx vault to decomission v3 staking
|
||||
function testCatastrophicFailureModeOnStaking() public {
|
||||
DelegatorPool[5] memory delegatorPools = [
|
||||
DelegatorPool(
|
||||
0x0ee1F33A2EB0da738FdF035C48d62d75e996a3bd,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000016
|
||||
),
|
||||
DelegatorPool(
|
||||
0xcAb3d8cBBb3dA1bDabfB003B9C828B27a821717f,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000017
|
||||
),
|
||||
DelegatorPool(
|
||||
0x7f88b00Db27a500fBfA7EbC9c3CaA2Dea6F59d5b,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000014
|
||||
),
|
||||
DelegatorPool(
|
||||
0xcE266E6123B682f7A7388097e2155b5379D9AC78,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000014
|
||||
),
|
||||
DelegatorPool(
|
||||
0xBa4f44E774158408E2DC6c5cb65BC995F0a89180, // pool operator
|
||||
0x0000000000000000000000000000000000000000000000000000000000000017
|
||||
)
|
||||
];
|
||||
|
||||
// Enter catastrophic failure mode on the zrx vault
|
||||
vm.prank(STAKING_AND_VAULT_OWNER);
|
||||
vault.enterCatastrophicFailure();
|
||||
vm.stopPrank();
|
||||
|
||||
// Stakes can still be withdrawn
|
||||
// staker1 withdraws
|
||||
uint256 stake1 = vault.balanceOf(staker1);
|
||||
uint256 balance1 = token.balanceOf(staker1);
|
||||
assertGt(stake1, 0);
|
||||
|
||||
vm.prank(staker1);
|
||||
vault.withdrawAllFrom(staker1);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(vault.balanceOf(staker1), 0);
|
||||
assertEq(token.balanceOf(staker1), stake1 + balance1);
|
||||
|
||||
// staker2 withdraws
|
||||
uint256 stake2 = vault.balanceOf(staker2);
|
||||
uint256 balance2 = token.balanceOf(staker2);
|
||||
assertGt(stake2, 0);
|
||||
|
||||
vm.prank(staker2);
|
||||
vault.withdrawAllFrom(staker2);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(vault.balanceOf(staker2), 0);
|
||||
assertEq(token.balanceOf(staker2), stake2 + balance2);
|
||||
|
||||
// Test top stakers can withdraw
|
||||
for (uint256 i = 0; i < topStakers.length; i++) {
|
||||
address staker = topStakers[i];
|
||||
uint256 stake = vault.balanceOf(staker);
|
||||
uint256 balance = token.balanceOf(staker);
|
||||
assertGt(stake, 0);
|
||||
|
||||
vm.prank(staker);
|
||||
vault.withdrawAllFrom(staker);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(vault.balanceOf(staker), 0);
|
||||
assertEq(token.balanceOf(staker), stake + balance);
|
||||
}
|
||||
|
||||
// Delegator can withdraw rewards
|
||||
for (uint256 i = 0; i < delegatorPools.length; i++) {
|
||||
address delegator = delegatorPools[i].delegator;
|
||||
bytes32 pool = delegatorPools[i].pool;
|
||||
uint256 reward = staking.computeRewardBalanceOfDelegator(pool, delegator);
|
||||
assertGt(reward, 0);
|
||||
uint256 balanceBeforeReward = weth.balanceOf(delegator);
|
||||
|
||||
vm.prank(delegator);
|
||||
staking.withdrawDelegatorRewards(pool);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(weth.balanceOf(delegator), balanceBeforeReward + reward);
|
||||
}
|
||||
}
|
||||
|
||||
function testSwitchDelegationInCatastrophicMode() public {
|
||||
// Enter catastrophic failure mode on the zrx vault
|
||||
vm.prank(STAKING_AND_VAULT_OWNER);
|
||||
vault.enterCatastrophicFailure();
|
||||
|
||||
// 0x delegator
|
||||
address delegator = 0x5775afA796818ADA27b09FaF5c90d101f04eF600;
|
||||
|
||||
uint256 stake = vault.balanceOf(delegator);
|
||||
uint256 balance = token.balanceOf(delegator);
|
||||
assertGt(stake, 0);
|
||||
|
||||
// Withdraw stake all at once
|
||||
vm.startPrank(delegator);
|
||||
vault.withdrawAllFrom(delegator);
|
||||
|
||||
assertEq(vault.balanceOf(delegator), 0);
|
||||
assertEq(token.balanceOf(delegator), stake + balance);
|
||||
|
||||
// delegate 1M ZRX to 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08
|
||||
vm.roll(block.number + 1);
|
||||
address delegate = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
|
||||
uint256 amountToDelegate = 1000000e18;
|
||||
|
||||
// Approve the wrapped token and deposit 1m ZRX
|
||||
token.approve(address(wToken), amountToDelegate);
|
||||
wToken.depositFor(delegator, amountToDelegate);
|
||||
|
||||
assertEq(wToken.balanceOf(delegator), amountToDelegate);
|
||||
|
||||
vm.roll(block.number + 1);
|
||||
wToken.delegate(delegate);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(votes.getVotes(delegate), amountToDelegate);
|
||||
assertEq(votes.getQuadraticVotes(delegate), amountToDelegate);
|
||||
}
|
||||
|
||||
function testSwitchDelegationInNormalOperationMode() public {
|
||||
// 0x delegator
|
||||
address delegator = 0x5775afA796818ADA27b09FaF5c90d101f04eF600;
|
||||
uint256 balance = token.balanceOf(delegator);
|
||||
|
||||
// Undelegate stake from pool 0x35
|
||||
vm.startPrank(delegator);
|
||||
staking.moveStake(
|
||||
IStructs.StakeInfo(
|
||||
IStructs.StakeStatus.DELEGATED,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000035
|
||||
),
|
||||
IStructs.StakeInfo(IStructs.StakeStatus.UNDELEGATED, bytes32(0)),
|
||||
3000000000000000000000000
|
||||
);
|
||||
|
||||
// Undelegate stake from pool 0x38
|
||||
IStructs.StoredBalance memory storedBalance38 = staking.getStakeDelegatedToPoolByOwner(
|
||||
delegator,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000038
|
||||
);
|
||||
staking.moveStake(
|
||||
IStructs.StakeInfo(
|
||||
IStructs.StakeStatus.DELEGATED,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000038
|
||||
),
|
||||
IStructs.StakeInfo(IStructs.StakeStatus.UNDELEGATED, bytes32(0)),
|
||||
storedBalance38.currentEpochBalance
|
||||
);
|
||||
|
||||
// Warp past an epochs and unstake
|
||||
uint256 epochEndTime = staking.getCurrentEpochEarliestEndTimeInSeconds();
|
||||
vm.warp(epochEndTime + 1);
|
||||
staking.endEpoch();
|
||||
|
||||
staking.unstake(6000000000000000000000000);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(token.balanceOf(delegator), balance + 2 * 3000000000000000000000000);
|
||||
|
||||
// delegate 1M ZRX to 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08
|
||||
vm.roll(block.number + 1);
|
||||
address delegate = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
|
||||
uint256 amountToDelegate = 1000000e18;
|
||||
|
||||
// Approve the wrapped token and deposit 1m ZRX
|
||||
token.approve(address(wToken), amountToDelegate);
|
||||
wToken.depositFor(delegator, amountToDelegate);
|
||||
|
||||
assertEq(wToken.balanceOf(delegator), amountToDelegate);
|
||||
|
||||
vm.roll(block.number + 1);
|
||||
wToken.delegate(delegate);
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(votes.getVotes(delegate), amountToDelegate);
|
||||
assertEq(votes.getQuadraticVotes(delegate), amountToDelegate);
|
||||
}
|
||||
}
|
21
contracts/governance/test/mocks/CubeRoot.sol
Normal file
21
contracts/governance/test/mocks/CubeRoot.sol
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
library CubeRoot {
|
||||
/// @dev Returns the cube root of `x`.
|
||||
/// Credit to pleasemarkdarkly under MIT license
|
||||
// Originaly from https://github.com/pleasemarkdarkly/fei-protocol-core-hh/blob/main/contracts/utils/Roots.sol
|
||||
function cbrt(uint y) internal pure returns (uint z) {
|
||||
// Newton's method https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
|
||||
if (y > 7) {
|
||||
z = y;
|
||||
uint x = y / 3 + 1;
|
||||
while (x < z) {
|
||||
z = x;
|
||||
x = (y / (x * x) + (2 * x)) / 3;
|
||||
}
|
||||
} else if (y != 0) {
|
||||
z = 1;
|
||||
}
|
||||
}
|
||||
}
|
36
contracts/governance/test/mocks/IOwnableFeature.sol
Normal file
36
contracts/governance/test/mocks/IOwnableFeature.sol
Normal file
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v08/interfaces/IOwnableV08.sol";
|
||||
|
||||
/// @dev Owner management and migration features.
|
||||
interface IOwnableFeature is IOwnableV08 {
|
||||
/// @dev Emitted when `migrate()` is called.
|
||||
/// @param caller The caller of `migrate()`.
|
||||
/// @param migrator The migration contract.
|
||||
/// @param newOwner The address of the new owner.
|
||||
event Migrated(address caller, address migrator, address newOwner);
|
||||
|
||||
/// @dev Execute a migration function in the context of the ZeroEx contract.
|
||||
/// The result of the function being called should be the magic bytes
|
||||
/// 0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner.
|
||||
/// The owner will be temporarily set to `address(this)` inside the call.
|
||||
/// Before returning, the owner will be set to `newOwner`.
|
||||
/// @param target The migrator contract address.
|
||||
/// @param newOwner The address of the new owner.
|
||||
/// @param data The call data.
|
||||
function migrate(address target, bytes calldata data, address newOwner) external;
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright 2023 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.8.19;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
/// @dev Basic registry management features.
|
||||
interface ISimpleFunctionRegistryFeature {
|
||||
/// @dev A function implementation was updated via `extend()` or `rollback()`.
|
||||
/// @param selector The function selector.
|
||||
/// @param oldImpl The implementation contract address being replaced.
|
||||
/// @param newImpl The replacement implementation contract address.
|
||||
event ProxyFunctionUpdated(bytes4 indexed selector, address oldImpl, address newImpl);
|
||||
|
||||
/// @dev Roll back to a prior implementation of a function.
|
||||
/// @param selector The function selector.
|
||||
/// @param targetImpl The address of an older implementation of the function.
|
||||
function rollback(bytes4 selector, address targetImpl) external;
|
||||
|
||||
/// @dev Register or replace a function.
|
||||
/// @param selector The function selector.
|
||||
/// @param impl The implementation contract for the function.
|
||||
function extend(bytes4 selector, address impl) external;
|
||||
|
||||
/// @dev Retrieve the length of the rollback history for a function.
|
||||
/// @param selector The function selector.
|
||||
/// @return rollbackLength The number of items in the rollback history for
|
||||
/// the function.
|
||||
function getRollbackLength(bytes4 selector) external view returns (uint256 rollbackLength);
|
||||
|
||||
/// @dev Retrieve an entry in the rollback history for a function.
|
||||
/// @param selector The function selector.
|
||||
/// @param idx The index in the rollback history.
|
||||
/// @return impl An implementation address for the function at
|
||||
/// index `idx`.
|
||||
function getRollbackEntryAtIndex(bytes4 selector, uint256 idx) external view returns (address impl);
|
||||
}
|
196
contracts/governance/test/mocks/IStakingMock.sol
Normal file
196
contracts/governance/test/mocks/IStakingMock.sol
Normal file
@@ -0,0 +1,196 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 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.
|
||||
|
||||
*/
|
||||
|
||||
import "./IZrxVaultMock.sol";
|
||||
import "./IStructs.sol";
|
||||
import "./IStorageMock.sol";
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
interface IStakingMock is IStorageMock {
|
||||
/// @dev Adds a new exchange address
|
||||
/// @param addr Address of exchange contract to add
|
||||
function addExchangeAddress(address addr) external;
|
||||
|
||||
/// @dev Create a new staking pool. The sender will be the operator of this pool.
|
||||
/// Note that an operator must be payable.
|
||||
/// @param operatorShare Portion of rewards owned by the operator, in ppm.
|
||||
/// @param addOperatorAsMaker Adds operator to the created pool as a maker for convenience iff true.
|
||||
/// @return poolId The unique pool id generated for this pool.
|
||||
function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker) external returns (bytes32 poolId);
|
||||
|
||||
/// @dev Decreases the operator share for the given pool (i.e. increases pool rewards for members).
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param newOperatorShare The newly decreased percentage of any rewards owned by the operator.
|
||||
function decreaseStakingPoolOperatorShare(bytes32 poolId, uint32 newOperatorShare) external;
|
||||
|
||||
/// @dev Begins a new epoch, preparing the prior one for finalization.
|
||||
/// Throws if not enough time has passed between epochs or if the
|
||||
/// previous epoch was not fully finalized.
|
||||
/// @return numPoolsToFinalize The number of unfinalized pools.
|
||||
function endEpoch() external returns (uint256);
|
||||
|
||||
/// @dev Instantly finalizes a single pool that earned rewards in the previous
|
||||
/// epoch, crediting it rewards for members and withdrawing operator's
|
||||
/// rewards as WETH. This can be called by internal functions that need
|
||||
/// to finalize a pool immediately. Does nothing if the pool is already
|
||||
/// finalized or did not earn rewards in the previous epoch.
|
||||
/// @param poolId The pool ID to finalize.
|
||||
function finalizePool(bytes32 poolId) external;
|
||||
|
||||
/// @dev Initialize storage owned by this contract.
|
||||
/// This function should not be called directly.
|
||||
/// The StakingProxy contract will call it in `attachStakingContract()`.
|
||||
function init() external;
|
||||
|
||||
/// @dev Allows caller to join a staking pool as a maker.
|
||||
/// @param poolId Unique id of pool.
|
||||
function joinStakingPoolAsMaker(bytes32 poolId) external;
|
||||
|
||||
/// @dev Moves stake between statuses: 'undelegated' or 'delegated'.
|
||||
/// Delegated stake can also be moved between pools.
|
||||
/// This change comes into effect next epoch.
|
||||
/// @param from status to move stake out of.
|
||||
/// @param to status to move stake into.
|
||||
/// @param amount of stake to move.
|
||||
function moveStake(IStructs.StakeInfo calldata from, IStructs.StakeInfo calldata to, uint256 amount) external;
|
||||
|
||||
/// @dev Pays a protocol fee in ETH.
|
||||
/// @param makerAddress The address of the order's maker.
|
||||
/// @param payerAddress The address that is responsible for paying the protocol fee.
|
||||
/// @param protocolFee The amount of protocol fees that should be paid.
|
||||
function payProtocolFee(address makerAddress, address payerAddress, uint256 protocolFee) external payable;
|
||||
|
||||
/// @dev Removes an existing exchange address
|
||||
/// @param addr Address of exchange contract to remove
|
||||
function removeExchangeAddress(address addr) external;
|
||||
|
||||
/// @dev Set all configurable parameters at once.
|
||||
/// @param _epochDurationInSeconds Minimum seconds between epochs.
|
||||
/// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
|
||||
/// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
|
||||
/// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
|
||||
/// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor.
|
||||
function setParams(
|
||||
uint256 _epochDurationInSeconds,
|
||||
uint32 _rewardDelegatedStakeWeight,
|
||||
uint256 _minimumPoolStake,
|
||||
uint32 _cobbDouglasAlphaNumerator,
|
||||
uint32 _cobbDouglasAlphaDenominator
|
||||
) external;
|
||||
|
||||
/// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault.
|
||||
/// Unstake to retrieve the ZRX. Stake is in the 'Active' status.
|
||||
/// @param amount of ZRX to stake.
|
||||
function stake(uint256 amount) external;
|
||||
|
||||
/// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to
|
||||
/// the staker. Stake must be in the 'undelegated' status in both the
|
||||
/// current and next epoch in order to be unstaked.
|
||||
/// @param amount of ZRX to unstake.
|
||||
function unstake(uint256 amount) external;
|
||||
|
||||
/// @dev Withdraws the caller's WETH rewards that have accumulated
|
||||
/// until the last epoch.
|
||||
/// @param poolId Unique id of pool.
|
||||
function withdrawDelegatorRewards(bytes32 poolId) external;
|
||||
|
||||
/// @dev Computes the reward balance in ETH of a specific member of a pool.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param member The member of the pool.
|
||||
/// @return reward Balance in ETH.
|
||||
function computeRewardBalanceOfDelegator(bytes32 poolId, address member) external view returns (uint256 reward);
|
||||
|
||||
/// @dev Computes the reward balance in ETH of the operator of a pool.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @return reward Balance in ETH.
|
||||
function computeRewardBalanceOfOperator(bytes32 poolId) external view returns (uint256 reward);
|
||||
|
||||
/// @dev Returns the earliest end time in seconds of this epoch.
|
||||
/// The next epoch can begin once this time is reached.
|
||||
/// Epoch period = [startTimeInSeconds..endTimeInSeconds)
|
||||
/// @return Time in seconds.
|
||||
function getCurrentEpochEarliestEndTimeInSeconds() external view returns (uint256);
|
||||
|
||||
/// @dev Gets global stake for a given status.
|
||||
/// @param stakeStatus UNDELEGATED or DELEGATED
|
||||
/// @return balance Global stake for given status.
|
||||
function getGlobalStakeByStatus(
|
||||
IStructs.StakeStatus stakeStatus
|
||||
) external view returns (IStructs.StoredBalance memory balance);
|
||||
|
||||
/// @dev Gets an owner's stake balances by status.
|
||||
/// @param staker Owner of stake.
|
||||
/// @param stakeStatus UNDELEGATED or DELEGATED
|
||||
/// @return balance Owner's stake balances for given status.
|
||||
function getOwnerStakeByStatus(
|
||||
address staker,
|
||||
IStructs.StakeStatus stakeStatus
|
||||
) external view returns (IStructs.StoredBalance memory balance);
|
||||
|
||||
/// @dev Retrieves all configurable parameter values.
|
||||
/// @return _epochDurationInSeconds Minimum seconds between epochs.
|
||||
/// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
|
||||
/// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
|
||||
/// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
|
||||
/// @return _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor.
|
||||
function getParams()
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256 _epochDurationInSeconds,
|
||||
uint32 _rewardDelegatedStakeWeight,
|
||||
uint256 _minimumPoolStake,
|
||||
uint32 _cobbDouglasAlphaNumerator,
|
||||
uint32 _cobbDouglasAlphaDenominator
|
||||
);
|
||||
|
||||
/// @param staker of stake.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @return balance Stake delegated to pool by staker.
|
||||
function getStakeDelegatedToPoolByOwner(
|
||||
address staker,
|
||||
bytes32 poolId
|
||||
) external view returns (IStructs.StoredBalance memory balance);
|
||||
|
||||
/// @dev Returns a staking pool
|
||||
/// @param poolId Unique id of pool.
|
||||
function getStakingPool(bytes32 poolId) external view returns (IStructs.Pool memory);
|
||||
|
||||
/// @dev Get stats on a staking pool in this epoch.
|
||||
/// @param poolId Pool Id to query.
|
||||
/// @return PoolStats struct for pool id.
|
||||
function getStakingPoolStatsThisEpoch(bytes32 poolId) external view returns (IStructs.PoolStats memory);
|
||||
|
||||
/// @dev Returns the total stake delegated to a specific staking pool,
|
||||
/// across all members.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @return balance Total stake delegated to pool.
|
||||
function getTotalStakeDelegatedToPool(bytes32 poolId) external view returns (IStructs.StoredBalance memory balance);
|
||||
|
||||
/// @dev An overridable way to access the deployed WETH contract.
|
||||
/// Must be view to allow overrides to access state.
|
||||
/// @return wethContract The WETH contract instance.
|
||||
function getWethContract() external view returns (address wethContract);
|
||||
|
||||
/// @dev An overridable way to access the deployed zrxVault.
|
||||
/// Must be view to allow overrides to access state.
|
||||
/// @return zrxVault The zrxVault contract.
|
||||
function getZrxVault() external view returns (IZrxVaultMock zrxVault);
|
||||
}
|
49
contracts/governance/test/mocks/IStorageMock.sol
Normal file
49
contracts/governance/test/mocks/IStorageMock.sol
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 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.8.19;
|
||||
|
||||
import "./IZrxVaultMock.sol";
|
||||
import "./IStructs.sol";
|
||||
|
||||
interface IStorageMock {
|
||||
function stakingContract() external view returns (address);
|
||||
|
||||
function lastPoolId() external view returns (bytes32);
|
||||
|
||||
function numMakersByPoolId(bytes32 poolId) external view returns (uint256);
|
||||
|
||||
function currentEpoch() external view returns (uint256);
|
||||
|
||||
function currentEpochStartTimeInSeconds() external view returns (uint256);
|
||||
|
||||
function protocolFeesThisEpochByPool(bytes32 poolId) external view returns (uint256);
|
||||
|
||||
function validExchanges(address exchangeAddress) external view returns (bool);
|
||||
|
||||
function epochDurationInSeconds() external view returns (uint256);
|
||||
|
||||
function rewardDelegatedStakeWeight() external view returns (uint32);
|
||||
|
||||
function minimumPoolStake() external view returns (uint256);
|
||||
|
||||
function cobbDouglasAlphaNumerator() external view returns (uint32);
|
||||
|
||||
function cobbDouglasAlphaDenominator() external view returns (uint32);
|
||||
}
|
92
contracts/governance/test/mocks/IStructs.sol
Normal file
92
contracts/governance/test/mocks/IStructs.sol
Normal file
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 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.8.19;
|
||||
|
||||
interface IStructs {
|
||||
/// @dev Stats for a pool that earned rewards.
|
||||
/// @param feesCollected Fees collected in ETH by this pool.
|
||||
/// @param weightedStake Amount of weighted stake in the pool.
|
||||
/// @param membersStake Amount of non-operator stake in the pool.
|
||||
struct PoolStats {
|
||||
uint256 feesCollected;
|
||||
uint256 weightedStake;
|
||||
uint256 membersStake;
|
||||
}
|
||||
|
||||
/// @dev Holds stats aggregated across a set of pools.
|
||||
/// @param rewardsAvailable Rewards (ETH) available to the epoch
|
||||
/// being finalized (the previous epoch). This is simply the balance
|
||||
/// of the contract at the end of the epoch.
|
||||
/// @param numPoolsToFinalize The number of pools that have yet to be finalized through `finalizePools()`.
|
||||
/// @param totalFeesCollected The total fees collected for the epoch being finalized.
|
||||
/// @param totalWeightedStake The total fees collected for the epoch being finalized.
|
||||
/// @param totalRewardsFinalized Amount of rewards that have been paid during finalization.
|
||||
struct AggregatedStats {
|
||||
uint256 rewardsAvailable;
|
||||
uint256 numPoolsToFinalize;
|
||||
uint256 totalFeesCollected;
|
||||
uint256 totalWeightedStake;
|
||||
uint256 totalRewardsFinalized;
|
||||
}
|
||||
|
||||
/// @dev Encapsulates a balance for the current and next epochs.
|
||||
/// Note that these balances may be stale if the current epoch
|
||||
/// is greater than `currentEpoch`.
|
||||
/// @param currentEpoch the current epoch
|
||||
/// @param currentEpochBalance balance in the current epoch.
|
||||
/// @param nextEpochBalance balance in `currentEpoch+1`.
|
||||
struct StoredBalance {
|
||||
uint64 currentEpoch;
|
||||
uint96 currentEpochBalance;
|
||||
uint96 nextEpochBalance;
|
||||
}
|
||||
|
||||
/// @dev Statuses that stake can exist in.
|
||||
/// Any stake can be (re)delegated effective at the next epoch
|
||||
/// Undelegated stake can be withdrawn if it is available in both the current and next epoch
|
||||
enum StakeStatus {
|
||||
UNDELEGATED,
|
||||
DELEGATED
|
||||
}
|
||||
|
||||
/// @dev Info used to describe a status.
|
||||
/// @param status of the stake.
|
||||
/// @param poolId Unique Id of pool. This is set when status=DELEGATED.
|
||||
struct StakeInfo {
|
||||
StakeStatus status;
|
||||
bytes32 poolId;
|
||||
}
|
||||
|
||||
/// @dev Struct to represent a fraction.
|
||||
/// @param numerator of fraction.
|
||||
/// @param denominator of fraction.
|
||||
struct Fraction {
|
||||
uint256 numerator;
|
||||
uint256 denominator;
|
||||
}
|
||||
|
||||
/// @dev Holds the metadata for a staking pool.
|
||||
/// @param operator of the pool.
|
||||
/// @param operatorShare Fraction of the total balance owned by the operator, in ppm.
|
||||
struct Pool {
|
||||
address operator;
|
||||
uint32 operatorShare;
|
||||
}
|
||||
}
|
@@ -1,34 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Copyright 2023 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.6;
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "./IOwnableFeature.sol";
|
||||
import "./ISimpleFunctionRegistryFeature.sol";
|
||||
|
||||
interface IUniswapV2Router01 {
|
||||
|
||||
function getAmountsOut(uint256 amountIn, address[] calldata path)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts);
|
||||
|
||||
function getAmountsIn(uint256 amountOut, address[] calldata path)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory amounts);
|
||||
/// @dev Minimal viable Exchange Proxy interface for governance use.
|
||||
interface IZeroExMock is IOwnableFeature, ISimpleFunctionRegistryFeature {
|
||||
/// @dev Fallback for just receiving ether.
|
||||
receive() external payable;
|
||||
}
|
159
contracts/governance/test/mocks/IZrxTreasuryMock.sol
Normal file
159
contracts/governance/test/mocks/IZrxTreasuryMock.sol
Normal file
@@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 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.8.19;
|
||||
|
||||
import "./IStakingMock.sol";
|
||||
|
||||
/// @dev Minimal viable Treasury interface for governance use.
|
||||
interface IZrxTreasuryMock {
|
||||
struct TreasuryParameters {
|
||||
uint256 votingPeriod;
|
||||
uint256 proposalThreshold;
|
||||
uint256 quorumThreshold;
|
||||
bytes32 defaultPoolId;
|
||||
}
|
||||
|
||||
struct ProposedAction {
|
||||
address target;
|
||||
bytes data;
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct Proposal {
|
||||
bytes32 actionsHash;
|
||||
uint256 executionEpoch;
|
||||
uint256 voteEpoch;
|
||||
uint256 votesFor;
|
||||
uint256 votesAgainst;
|
||||
bool executed;
|
||||
}
|
||||
|
||||
event ProposalCreated(
|
||||
address proposer,
|
||||
bytes32[] operatedPoolIds,
|
||||
uint256 proposalId,
|
||||
ProposedAction[] actions,
|
||||
uint256 executionEpoch,
|
||||
string description
|
||||
);
|
||||
|
||||
event VoteCast(address voter, bytes32[] operatedPoolIds, uint256 proposalId, bool support, uint256 votingPower);
|
||||
|
||||
event ProposalExecuted(uint256 proposalId);
|
||||
|
||||
function stakingProxy() external view returns (IStakingMock);
|
||||
|
||||
function defaultPoolId() external view returns (bytes32);
|
||||
|
||||
function votingPeriod() external view returns (uint256);
|
||||
|
||||
function proposalThreshold() external view returns (uint256);
|
||||
|
||||
function quorumThreshold() external view returns (uint256);
|
||||
|
||||
/// @dev Updates the proposal and quorum thresholds to the given
|
||||
/// values. Note that this function is only callable by the
|
||||
/// treasury contract itself, so the threshold can only be
|
||||
/// updated via a successful treasury proposal.
|
||||
/// @param newProposalThreshold The new value for the proposal threshold.
|
||||
/// @param newQuorumThreshold The new value for the quorum threshold.
|
||||
function updateThresholds(uint256 newProposalThreshold, uint256 newQuorumThreshold) external;
|
||||
|
||||
/// @dev Creates a proposal to send ZRX from this treasury on the
|
||||
/// the given actions. Must have at least `proposalThreshold`
|
||||
/// of voting power to call this function. See `getVotingPower`
|
||||
/// for how voting power is computed. If a proposal is successfully
|
||||
/// created, voting starts at the epoch after next (currentEpoch + 2).
|
||||
/// If the vote passes, the proposal is executable during the
|
||||
/// `executionEpoch`. See `hasProposalPassed` for the passing criteria.
|
||||
/// @param actions The proposed ZRX actions. An action specifies a
|
||||
/// contract call.
|
||||
/// @param executionEpoch The epoch during which the proposal is to
|
||||
/// be executed if it passes. Must be at least two epochs
|
||||
/// from the current epoch.
|
||||
/// @param description A text description for the proposal.
|
||||
/// @param operatedPoolIds The pools operated by `msg.sender`. The
|
||||
/// ZRX currently delegated to those pools will be accounted
|
||||
/// for in the voting power.
|
||||
/// @return proposalId The ID of the newly created proposal.
|
||||
function propose(
|
||||
ProposedAction[] calldata actions,
|
||||
uint256 executionEpoch,
|
||||
string calldata description,
|
||||
bytes32[] calldata operatedPoolIds
|
||||
) external returns (uint256 proposalId);
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
/// during the voting period for that proposal.
|
||||
/// One address can only vote once.
|
||||
/// See `getVotingPower` for how voting power is computed.
|
||||
/// @param proposalId The ID of the proposal to vote on.
|
||||
/// @param support Whether to support the proposal or not.
|
||||
/// @param operatedPoolIds The pools operated by `msg.sender`. The
|
||||
/// ZRX currently delegated to those pools will be accounted
|
||||
/// for in the voting power.
|
||||
function castVote(uint256 proposalId, bool support, bytes32[] calldata operatedPoolIds) external;
|
||||
|
||||
/// @dev Casts a vote for the given proposal, by signature.
|
||||
/// Only callable during the voting period for that proposal.
|
||||
/// One address/voter can only vote once.
|
||||
/// See `getVotingPower` for how voting power is computed.
|
||||
/// @param proposalId The ID of the proposal to vote on.
|
||||
/// @param support Whether to support the proposal or not.
|
||||
/// @param operatedPoolIds The pools operated by the signer. The
|
||||
/// ZRX currently delegated to those pools will be accounted
|
||||
/// for in the voting power.
|
||||
/// @param v the v field of the signature
|
||||
/// @param r the r field of the signature
|
||||
/// @param s the s field of the signature
|
||||
function castVoteBySignature(
|
||||
uint256 proposalId,
|
||||
bool support,
|
||||
bytes32[] memory operatedPoolIds,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) external;
|
||||
|
||||
/// @dev Executes a proposal that has passed and is
|
||||
/// currently executable.
|
||||
/// @param proposalId The ID of the proposal to execute.
|
||||
/// @param actions Actions associated with the proposal to execute.
|
||||
function execute(uint256 proposalId, ProposedAction[] memory actions) external payable;
|
||||
|
||||
/// @dev Returns the total number of proposals.
|
||||
/// @return count The number of proposals.
|
||||
function proposalCount() external view returns (uint256 count);
|
||||
|
||||
/// @dev Computes the current voting power of the given account.
|
||||
/// Voting power is equal to:
|
||||
/// (ZRX delegated to the default pool) +
|
||||
/// 0.5 * (ZRX delegated to other pools) +
|
||||
/// 0.5 * (ZRX delegated to pools operated by account)
|
||||
/// @param account The address of the account.
|
||||
/// @param operatedPoolIds The pools operated by `account`. The
|
||||
/// ZRX currently delegated to those pools will be accounted
|
||||
/// for in the voting power.
|
||||
/// @return votingPower The current voting power of the given account.
|
||||
function getVotingPower(
|
||||
address account,
|
||||
bytes32[] calldata operatedPoolIds
|
||||
) external view returns (uint256 votingPower);
|
||||
}
|
83
contracts/governance/test/mocks/IZrxVaultMock.sol
Normal file
83
contracts/governance/test/mocks/IZrxVaultMock.sol
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
|
||||
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.8.19;
|
||||
|
||||
interface IZrxVaultMock {
|
||||
/// @dev Emmitted whenever a StakingProxy is set in a vault.
|
||||
event StakingProxySet(address stakingProxyAddress);
|
||||
|
||||
/// @dev Emitted when the Staking contract is put into Catastrophic Failure Mode
|
||||
/// @param sender Address of sender (`msg.sender`)
|
||||
event InCatastrophicFailureMode(address sender);
|
||||
|
||||
/// @dev Emitted when Zrx Tokens are deposited into the vault.
|
||||
/// @param staker of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens deposited.
|
||||
event Deposit(address indexed staker, uint256 amount);
|
||||
|
||||
/// @dev Emitted when Zrx Tokens are withdrawn from the vault.
|
||||
/// @param staker of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens withdrawn.
|
||||
event Withdraw(address indexed staker, uint256 amount);
|
||||
|
||||
/// @dev Emitted whenever the ZRX AssetProxy is set.
|
||||
event ZrxProxySet(address zrxProxyAddress);
|
||||
|
||||
/// @dev Sets the address of the StakingProxy contract.
|
||||
/// Note that only the contract staker can call this function.
|
||||
/// @param _stakingProxyAddress Address of Staking proxy contract.
|
||||
function setStakingProxy(address _stakingProxyAddress) external;
|
||||
|
||||
/// @dev Vault enters into Catastrophic Failure Mode.
|
||||
/// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! ***
|
||||
/// Note that only the contract staker can call this function.
|
||||
function enterCatastrophicFailure() external;
|
||||
|
||||
/// @dev Sets the Zrx proxy.
|
||||
/// Note that only the contract staker can call this.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param zrxProxyAddress Address of the 0x Zrx Proxy.
|
||||
function setZrxProxy(address zrxProxyAddress) external;
|
||||
|
||||
/// @dev Deposit an `amount` of Zrx Tokens from `staker` into the vault.
|
||||
/// Note that only the Staking contract can call this.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param staker of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens to deposit.
|
||||
function depositFrom(address staker, uint256 amount) external;
|
||||
|
||||
/// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault.
|
||||
/// Note that only the Staking contract can call this.
|
||||
/// Note that this can only be called when *not* in Catastrophic Failure mode.
|
||||
/// @param staker of Zrx Tokens.
|
||||
/// @param amount of Zrx Tokens to withdraw.
|
||||
function withdrawFrom(address staker, uint256 amount) external;
|
||||
|
||||
/// @dev Withdraw ALL Zrx Tokens to `staker` from the vault.
|
||||
/// Note that this can only be called when *in* Catastrophic Failure mode.
|
||||
/// @param staker of Zrx Tokens.
|
||||
function withdrawAllFrom(address staker) external returns (uint256);
|
||||
|
||||
/// @dev Returns the balance in Zrx Tokens of the `staker`
|
||||
/// @return Balance in Zrx.
|
||||
function balanceOf(address staker) external view returns (uint256);
|
||||
|
||||
/// @dev Returns the entire balance of Zrx tokens in the vault.
|
||||
function balanceOfZrxVault() external view returns (uint256);
|
||||
}
|
31
contracts/governance/test/mocks/ZRXMock.sol
Normal file
31
contracts/governance/test/mocks/ZRXMock.sol
Normal file
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 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.8.19;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "@openzeppelin/token/ERC20/ERC20.sol";
|
||||
|
||||
// TODO remove this contract and work with an instance of ZRX compiled with 0.4
|
||||
// when the following is resolved https://linear.app/0xproject/issue/PRO-44/zrx-artifact-is-incompatible-with-foundry
|
||||
contract ZRXMock is ERC20 {
|
||||
constructor() ERC20("0x Protocol Token", "ZRX") {
|
||||
_mint(msg.sender, 10 ** 27);
|
||||
}
|
||||
}
|
11
contracts/governance/test/mocks/ZeroExMock.sol
Normal file
11
contracts/governance/test/mocks/ZeroExMock.sol
Normal file
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
contract ZeroExMock {
|
||||
mapping(bytes4 => address) public implementations;
|
||||
|
||||
function rollback(bytes4 selector, address targetImpl) public {
|
||||
implementations[selector] = targetImpl;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user