Compare commits
8 Commits
@0x/contra
...
phil/omicr
Author | SHA1 | Date | |
---|---|---|---|
|
9c9a9f73ae | ||
|
ae6f12db0d | ||
|
5efcab14d2 | ||
|
ded58fe133 | ||
|
fe1fcc73b1 | ||
|
783a83def2 | ||
|
f5635dc392 | ||
|
bb09fd2499 |
225
.circleci/config.yml
Normal file
225
.circleci/config.yml
Normal file
@@ -0,0 +1,225 @@
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
resource_class: xlarge
|
||||
docker:
|
||||
- image: node:16
|
||||
environment:
|
||||
NODE_OPTIONS: '--max-old-space-size=16384'
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init --recursive
|
||||
- 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
|
||||
- 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:16
|
||||
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:16
|
||||
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:16
|
||||
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:16
|
||||
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:16
|
||||
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-foundry:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: ghcr.io/foundry-rs/foundry:latest
|
||||
working_directory: ~/repo/contracts/zero-ex
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
# - run: forge install
|
||||
- run: forge test -vvv
|
||||
test-publish:
|
||||
resource_class: large
|
||||
environment:
|
||||
NODE_OPTIONS: '--max-old-space-size=6442'
|
||||
docker:
|
||||
- image: node:16
|
||||
- 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:16
|
||||
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:16
|
||||
working_directory: ~/repo
|
||||
environment:
|
||||
RUST_ROUTER: 'true'
|
||||
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-addresses -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/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:16
|
||||
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:16
|
||||
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-foundry:
|
||||
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
|
8
.github/autolabeler.yml
vendored
8
.github/autolabeler.yml
vendored
@@ -1,2 +1,6 @@
|
||||
documentation: ['docs']
|
||||
liquidity integrations: ['contracts/zero-ex/contracts/src/transformers']
|
||||
python: ['python-packages']
|
||||
contracts: ['contracts']
|
||||
@0x/contract-addresses: ['packages/contract-addresses']
|
||||
@0x/order-utils: ['packages/order-utils']
|
||||
@0x/contract-artifacts: ['packages/contract-artifacts']
|
||||
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||
|
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -1,7 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: monthly
|
||||
target-branch: "development"
|
19
.github/stale.yml
vendored
Normal file
19
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# 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.
|
137
.github/workflows/ci.yml
vendored
137
.github/workflows/ci.yml
vendored
@@ -1,137 +0,0 @@
|
||||
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: 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: Add foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
- 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'
|
40
.github/workflows/stale.yml
vendored
40
.github/workflows/stale.yml
vendored
@@ -1,40 +0,0 @@
|
||||
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
|
107
.gitignore
vendored
107
.gitignore
vendored
@@ -15,6 +15,9 @@ pids
|
||||
*.db
|
||||
*.sqlite
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
@@ -77,22 +80,104 @@ TODO.md
|
||||
.idea
|
||||
|
||||
# generated contract artifacts/
|
||||
generated-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 contract wrappers
|
||||
generated-wrappers/
|
||||
|
||||
# forge std-lib
|
||||
contracts/zero-ex/contracts/deps/forge-std
|
||||
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/
|
||||
|
||||
# foundry artifacts
|
||||
foundry-artifacts/
|
||||
contracts/zero-ex/foundry-artifacts/
|
||||
|
||||
# foundry cache
|
||||
cache/
|
||||
|
||||
#foundry output artifacts
|
||||
out/
|
||||
# foundry cache
|
||||
contracts/zero-ex/foundry-cache/
|
||||
|
||||
# typechain wrappers
|
||||
contracts/zero-ex/typechain-wrappers/
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +1,6 @@
|
||||
[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/utils/contracts/src/openzeppelin-contracts"]
|
||||
path = contracts/utils/contracts/src/openzeppelin-contracts
|
||||
url = https://github.com/OpenZeppelin/openzeppelin-contracts
|
||||
|
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged --no-stash
|
@@ -1,10 +1,90 @@
|
||||
lib
|
||||
deps
|
||||
.nyc_output
|
||||
generated-artifacts/
|
||||
generated-wrappers/
|
||||
foundry-artifacts/
|
||||
out/
|
||||
cache/
|
||||
/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
|
||||
package.json
|
||||
packages
|
||||
packages/*/docs
|
||||
docs/
|
||||
*.sol
|
||||
|
14
.prettierrc
14
.prettierrc
@@ -4,17 +4,5 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "avoid",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.sol",
|
||||
"options": {
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": false
|
||||
}
|
||||
}
|
||||
]
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
contracts/erc20/src/ZRXToken.sol
|
||||
node_modules/
|
||||
lib
|
||||
deps
|
||||
generated-artifacts/
|
||||
generated-wrappers/
|
||||
foundry-artifacts/
|
||||
out/
|
||||
cache/
|
@@ -6,9 +6,11 @@
|
||||
|
||||
# https://git-scm.com/docs/gitignore#_pattern_format
|
||||
|
||||
packages/asset-swapper/ @dekz @dextracker @kyu-c
|
||||
|
||||
# Dev tools & setup
|
||||
|
||||
.github/ @dekz
|
||||
.circleci/ @dekz
|
||||
packages/contract-addresses/ @dekz @dextracker @kyu-c
|
||||
packages/contract-artifacts/ @dekz
|
||||
packages/protocol-utils/ @dekz
|
@@ -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 [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))
|
||||
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))
|
||||
|
||||
Before making the PR "Ready for review", make sure:
|
||||
Before removing the `[WIP]` tag and submitting the PR 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](#fix-submit-coverage-ci-failure) 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](#enabling-code-coverage-checks-on-your-fork) 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,14 +59,16 @@ We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text
|
||||
|
||||
#### Linter
|
||||
|
||||
We use [ESLint](https://eslint.org/docs/latest/) to keep our code-style consistent.
|
||||
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.
|
||||
|
||||
Use `yarn lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
|
||||
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.
|
||||
|
||||
Integrate it into your text editor:
|
||||
|
||||
- VSCode: [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
||||
- Atom: [ESLint](https://atom.io/packages/eslint)
|
||||
- VSCode: [vscode-tslint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint)
|
||||
- Atom: [linter-tslint](https://atom.io/packages/linter-tslint)
|
||||
|
||||
#### Auto-formatter
|
||||
|
||||
@@ -89,3 +91,15 @@ 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.
|
@@ -2,13 +2,15 @@
|
||||
|
||||
<!--- 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 https://github.com/0xProject/ZEIPs -->
|
||||
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo -->
|
||||
|
||||
## Current Behavior
|
||||
|
||||
@@ -48,8 +50,8 @@
|
||||
| ------: | :------ |
|
||||
|
||||
<!-- For example:
|
||||
| `protocol-utils` | 2.0.4 |
|
||||
| `Exchange Contract` | v3 |
|
||||
| `0x.js` | 2.0.4 |
|
||||
| `Exchange Contract` | v2 |
|
||||
-->
|
||||
|
||||
| Network |
|
||||
@@ -58,6 +60,6 @@
|
||||
|
||||
<!-- For example:
|
||||
| mainnet |
|
||||
| goerli |
|
||||
| development |
|
||||
| kovan |
|
||||
| testrpc |
|
||||
-->
|
@@ -20,6 +20,7 @@
|
||||
|
||||
<!--- 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.
|
18
README.md
18
README.md
@@ -8,7 +8,8 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
|
||||
|
||||
[website-url]: https://0x.org
|
||||
|
||||
[](https://coveralls.io/github/0xProject/protocol?branch=development)
|
||||
[](https://circleci.com/gh/0xProject/protocool)
|
||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
|
||||
[](https://discordapp.com/invite/d3FTX3M)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
@@ -33,6 +34,7 @@ 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 |
|
||||
@@ -53,7 +55,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](.github/CONTRIBUTING.md).
|
||||
#### Read our [contribution guidelines](./CONTRIBUTING.md).
|
||||
|
||||
### Install dependencies
|
||||
|
||||
@@ -80,7 +82,7 @@ yarn build
|
||||
To build a specific package:
|
||||
|
||||
```bash
|
||||
PKG=@0x/protocol-utils yarn build
|
||||
PKG=@0x/asset-swapper yarn build
|
||||
```
|
||||
|
||||
To build all contracts packages:
|
||||
@@ -103,7 +105,7 @@ To watch a specific package and all it's dependent packages:
|
||||
PKG=[NPM_PACKAGE_NAME] yarn watch
|
||||
|
||||
e.g
|
||||
PKG=@0x/protocol-utils yarn watch
|
||||
PKG=@0x/asset-swapper yarn watch
|
||||
```
|
||||
|
||||
### Clean
|
||||
@@ -117,7 +119,7 @@ yarn clean
|
||||
Clean a specific package
|
||||
|
||||
```bash
|
||||
PKG=@0x/protocol-utils yarn clean
|
||||
PKG=@0x/asset-swapper yarn clean
|
||||
```
|
||||
|
||||
### Rebuild
|
||||
@@ -131,7 +133,7 @@ yarn rebuild
|
||||
To re-build (clean & build) a specific package & it's deps:
|
||||
|
||||
```bash
|
||||
PKG=@0x/protocol-utils yarn rebuild
|
||||
PKG=@0x/asset-swapper yarn rebuild
|
||||
```
|
||||
|
||||
### Lint
|
||||
@@ -145,7 +147,7 @@ yarn lint
|
||||
Lint a specific package:
|
||||
|
||||
```bash
|
||||
PKG=@0x/protocol-utils yarn lint
|
||||
PKG=@0x/asset-swapper yarn lint
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
@@ -159,7 +161,7 @@ yarn test
|
||||
Run a specific package's test:
|
||||
|
||||
```bash
|
||||
PKG=@0x/protocol-utils yarn test
|
||||
PKG=@0x/asset-swapper yarn test
|
||||
```
|
||||
|
||||
Run all contracts packages tests:
|
||||
|
22
contracts/.solhint.json
Normal file
22
contracts/.solhint.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"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
contracts/erc20/.solhintignore
Normal file
1
contracts/erc20/.solhintignore
Normal file
@@ -0,0 +1 @@
|
||||
contracts/src/ZRXToken.sol
|
@@ -1,211 +1,4 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
|
@@ -5,98 +5,6 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## 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
|
||||
|
@@ -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](../../.github/CONTRIBUTING.md) before getting started.
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
@@ -67,3 +67,7 @@ yarn lint
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
#### Testing options
|
||||
|
||||
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
||||
|
28
contracts/erc20/compiler.json
Normal file
28
contracts/erc20/compiler.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
148
contracts/erc20/contracts/src/ERC20Token.sol
Normal file
148
contracts/erc20/contracts/src/ERC20Token.sol
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
199
contracts/erc20/contracts/src/LibERC20Token.sol
Normal file
199
contracts/erc20/contracts/src/LibERC20Token.sol
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
61
contracts/erc20/contracts/src/MintableERC20Token.sol
Normal file
61
contracts/erc20/contracts/src/MintableERC20Token.sol
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -13,55 +13,58 @@
|
||||
// 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, 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);
|
||||
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 => uint256) public balanceOf;
|
||||
mapping(address => mapping(address => uint256)) public allowance;
|
||||
mapping (address => uint) public balanceOf;
|
||||
mapping (address => mapping (address => uint)) public allowance;
|
||||
|
||||
function() external payable {
|
||||
deposit();
|
||||
}
|
||||
|
||||
function deposit() public payable {
|
||||
balanceOf[msg.sender] += msg.value;
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function withdraw(uint256 wad) public {
|
||||
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 (uint256) {
|
||||
function totalSupply() public view returns (uint) {
|
||||
return address(this).balance;
|
||||
}
|
||||
|
||||
function approve(address guy, uint256 wad) public returns (bool) {
|
||||
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, uint256 wad) public returns (bool) {
|
||||
function transfer(address dst, uint wad) public returns (bool) {
|
||||
return transferFrom(msg.sender, dst, wad);
|
||||
}
|
||||
|
||||
function transferFrom(address src, address dst, uint256 wad) public returns (bool) {
|
||||
function transferFrom(address src, address dst, uint wad)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
require(balanceOf[src] >= wad);
|
||||
|
||||
if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
|
||||
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
|
||||
require(allowance[src][msg.sender] >= wad);
|
||||
allowance[src][msg.sender] -= wad;
|
||||
}
|
||||
@@ -75,6 +78,7 @@ contract WETH9 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
@@ -18,99 +18,105 @@
|
||||
|
||||
pragma solidity 0.4.11;
|
||||
|
||||
|
||||
contract Token {
|
||||
|
||||
/// @return total amount of tokens
|
||||
function totalSupply() constant returns (uint256 supply) {}
|
||||
function totalSupply() constant returns (uint supply) {}
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return The balance
|
||||
function balanceOf(address _owner) constant returns (uint256 balance) {}
|
||||
function balanceOf(address _owner) constant returns (uint 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, uint256 _value) returns (bool success) {}
|
||||
function transfer(address _to, uint _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, uint256 _value) returns (bool success) {}
|
||||
function transferFrom(address _from, address _to, uint _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, uint256 _value) returns (bool success) {}
|
||||
function approve(address _spender, uint _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 (uint256 remaining) {}
|
||||
function allowance(address _owner, address _spender) constant returns (uint remaining) {}
|
||||
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
event Transfer(address indexed _from, address indexed _to, uint _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint _value);
|
||||
}
|
||||
|
||||
|
||||
contract ERC20Token is Token {
|
||||
function transfer(address _to, uint256 _value) returns (bool) {
|
||||
|
||||
function transfer(address _to, uint _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, uint256 _value) returns (bool) {
|
||||
if (
|
||||
balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]
|
||||
) {
|
||||
function transferFrom(address _from, address _to, uint _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 (uint256) {
|
||||
function balanceOf(address _owner) constant returns (uint) {
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
function approve(address _spender, uint256 _value) returns (bool) {
|
||||
function approve(address _spender, uint _value) returns (bool) {
|
||||
allowed[msg.sender][_spender] = _value;
|
||||
Approval(msg.sender, _spender, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address _owner, address _spender) constant returns (uint256) {
|
||||
function allowance(address _owner, address _spender) constant returns (uint) {
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
|
||||
mapping(address => uint256) balances;
|
||||
mapping(address => mapping(address => uint256)) allowed;
|
||||
uint256 public totalSupply;
|
||||
mapping (address => uint) balances;
|
||||
mapping (address => mapping (address => uint)) allowed;
|
||||
uint public totalSupply;
|
||||
}
|
||||
|
||||
|
||||
contract UnlimitedAllowanceToken is ERC20Token {
|
||||
uint256 constant MAX_UINT = 2 ** 256 - 1;
|
||||
|
||||
uint 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, uint256 _value) public returns (bool) {
|
||||
uint256 allowance = allowed[_from][msg.sender];
|
||||
if (balances[_from] >= _value && allowance >= _value && balances[_to] + _value >= balances[_to]) {
|
||||
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]
|
||||
) {
|
||||
balances[_to] += _value;
|
||||
balances[_from] -= _value;
|
||||
if (allowance < MAX_UINT) {
|
||||
@@ -124,13 +130,21 @@ 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";
|
||||
|
||||
function ZRXToken() public {
|
||||
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
|
||||
{
|
||||
balances[msg.sender] = totalSupply;
|
||||
}
|
||||
}
|
87
contracts/erc20/contracts/src/interfaces/IERC20Token.sol
Normal file
87
contracts/erc20/contracts/src/interfaces/IERC20Token.sol
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
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);
|
||||
}
|
33
contracts/erc20/contracts/src/interfaces/IEtherToken.sol
Normal file
33
contracts/erc20/contracts/src/interfaces/IEtherToken.sol
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
|
||||
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,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2023 ZeroEx Intl.
|
||||
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.
|
||||
@@ -17,47 +17,80 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity >=0.6.5 <0.9;
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
interface IERC20Token {
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
|
||||
event Approval(address indexed owner, address indexed spender, 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
|
||||
);
|
||||
|
||||
/// @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,9 +19,12 @@
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "./IERC20Token.sol";
|
||||
import "./IERC20TokenV06.sol";
|
||||
|
||||
interface IEtherToken is IERC20Token {
|
||||
|
||||
interface IEtherTokenV06 is
|
||||
IERC20TokenV06
|
||||
{
|
||||
/// @dev Wrap ether.
|
||||
function deposit() external payable;
|
||||
|
@@ -21,51 +21,90 @@ 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 "../IERC20Token.sol";
|
||||
import "./IERC20TokenV06.sol";
|
||||
|
||||
|
||||
library LibERC20TokenV06 {
|
||||
bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
|
||||
bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()`.
|
||||
/// @dev Calls `IERC20TokenV06(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.encodeWithSelector(token.approve.selector, spender, allowance);
|
||||
function compatApprove(
|
||||
IERC20TokenV06 token,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.approve.selector,
|
||||
spender,
|
||||
allowance
|
||||
);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
|
||||
/// @dev Calls `IERC20TokenV06(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 {
|
||||
function approveIfBelow(
|
||||
IERC20TokenV06 token,
|
||||
address spender,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (token.allowance(address(this), spender) < amount) {
|
||||
compatApprove(token, spender, uint256(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transfer()`.
|
||||
/// @dev Calls `IERC20TokenV06(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.encodeWithSelector(token.transfer.selector, to, amount);
|
||||
function compatTransfer(
|
||||
IERC20TokenV06 token,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.transfer.selector,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transferFrom()`.
|
||||
/// @dev Calls `IERC20TokenV06(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.encodeWithSelector(token.transferFrom.selector, from, to, amount);
|
||||
function compatTransferFrom(
|
||||
IERC20TokenV06 token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
@@ -73,7 +112,11 @@ 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(IERC20Token token) internal view returns (uint8 tokenDecimals) {
|
||||
function compatDecimals(IERC20TokenV06 token)
|
||||
internal
|
||||
view
|
||||
returns (uint8 tokenDecimals)
|
||||
{
|
||||
tokenDecimals = 18;
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
|
||||
if (didSucceed && resultData.length >= 32) {
|
||||
@@ -87,13 +130,17 @@ 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(
|
||||
IERC20Token token,
|
||||
address owner,
|
||||
address spender
|
||||
) internal view returns (uint256 allowance_) {
|
||||
function compatAllowance(IERC20TokenV06 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);
|
||||
@@ -105,9 +152,16 @@ 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(IERC20Token token, address owner) internal view returns (uint256 balance) {
|
||||
function compatBalanceOf(IERC20TokenV06 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);
|
||||
@@ -119,7 +173,12 @@ 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) {
|
||||
@@ -129,9 +188,7 @@ 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;
|
||||
}
|
@@ -16,28 +16,27 @@
|
||||
// solhint-disable
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
|
||||
contract WETH9V06 {
|
||||
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, 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;
|
||||
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;
|
||||
@@ -59,7 +58,10 @@ contract WETH9V06 {
|
||||
return transferFrom(msg.sender, dst, wad);
|
||||
}
|
||||
|
||||
function transferFrom(address src, address dst, uint wad) public returns (bool) {
|
||||
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)) {
|
||||
@@ -76,6 +78,7 @@ contract WETH9V06 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
80
contracts/erc20/contracts/test/DummyERC20Token.sol
Normal file
80
contracts/erc20/contracts/test/DummyERC20Token.sol
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
contracts/erc20/contracts/test/DummyNoReturnERC20Token.sol
Normal file
115
contracts/erc20/contracts/test/DummyNoReturnERC20Token.sol
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
84
contracts/erc20/contracts/test/TestLibERC20Token.sol
Normal file
84
contracts/erc20/contracts/test/TestLibERC20Token.sol
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
106
contracts/erc20/contracts/test/TestLibERC20TokenTarget.sol
Normal file
106
contracts/erc20/contracts/test/TestLibERC20TokenTarget.sol
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
|
||||
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)) }
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +0,0 @@
|
||||
[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
|
Submodule contracts/erc20/lib/forge-std deleted from a2edd39db9
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "4.0.1",
|
||||
"version": "3.3.36",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -10,10 +10,37 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test:ci": "forge test",
|
||||
"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",
|
||||
"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|WETH9V06|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"
|
||||
@@ -22,11 +49,41 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/contracts-utils": "^4.8.39",
|
||||
"@0x/abi-gen": "^5.8.1",
|
||||
"@0x/contracts-gen": "^2.0.47",
|
||||
"@0x/contracts-test-utils": "^5.4.27",
|
||||
"@0x/contracts-utils": "^4.8.17",
|
||||
"@0x/dev-utils": "^5.0.0",
|
||||
"@0x/sol-compiler": "^4.8.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"typedoc": "~0.16.11"
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
"@0x/utils": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^8.0.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.7.1",
|
||||
"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.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"ethers": "~4.0.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
21
contracts/erc20/src/artifacts.ts
Normal file
21
contracts/erc20/src/artifacts.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* 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,
|
||||
};
|
47
contracts/erc20/src/index.ts
Normal file
47
contracts/erc20/src/index.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
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';
|
@@ -1,146 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
11
contracts/erc20/src/wrappers.ts
Normal file
11
contracts/erc20/src/wrappers.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* 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';
|
@@ -1,76 +0,0 @@
|
||||
// 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}();
|
||||
vm.stopPrank();
|
||||
|
||||
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);
|
||||
vm.stopPrank();
|
||||
|
||||
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));
|
||||
vm.stopPrank();
|
||||
|
||||
assertEq(etherToken.balanceOf(user), 1e20);
|
||||
assertEq(address(etherToken).balance, 1e20);
|
||||
}
|
||||
}
|
@@ -1,117 +0,0 @@
|
||||
// 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))
|
||||
}
|
||||
vm.stopPrank();
|
||||
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);
|
||||
vm.stopPrank();
|
||||
|
||||
bool success = zrxToken.transferFrom(owner, user, totalSupply + 1);
|
||||
assertEq(success, false);
|
||||
}
|
||||
|
||||
function testShouldReturnFalseIfRecipientHasInsufficientAllowance() public {
|
||||
vm.prank(owner);
|
||||
zrxToken.approve(user, totalSupply - 1);
|
||||
vm.stopPrank();
|
||||
|
||||
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);
|
||||
vm.stopPrank();
|
||||
|
||||
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.stopPrank();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
45
contracts/erc20/test/artifacts.ts
Normal file
45
contracts/erc20/test/artifacts.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* 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 WETH9V06 from '../test/generated-artifacts/WETH9V06.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,
|
||||
WETH9V06: WETH9V06 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,
|
||||
};
|
19
contracts/erc20/test/global_hooks.ts
Normal file
19
contracts/erc20/test/global_hooks.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { env, EnvVars } from '@0x/dev-utils';
|
||||
|
||||
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
|
||||
import { providerUtils } from '@0x/utils';
|
||||
|
||||
before('start web3 provider', () => {
|
||||
providerUtils.startProviderEngine(provider);
|
||||
});
|
||||
after('generate coverage report', async () => {
|
||||
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
await coverageSubprovider.writeCoverageAsync();
|
||||
}
|
||||
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
await profilerSubprovider.writeProfilerOutputAsync();
|
||||
}
|
||||
provider.stop();
|
||||
});
|
335
contracts/erc20/test/lib_erc20_token.ts
Normal file
335
contracts/erc20/test/lib_erc20_token.ts
Normal file
@@ -0,0 +1,335 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
187
contracts/erc20/test/unlimited_allowance_token.ts
Normal file
187
contracts/erc20/test/unlimited_allowance_token.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
149
contracts/erc20/test/weth9.ts
Normal file
149
contracts/erc20/test/weth9.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
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));
|
||||
});
|
||||
});
|
||||
});
|
23
contracts/erc20/test/wrappers.ts
Normal file
23
contracts/erc20/test/wrappers.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* 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/weth9v06';
|
||||
export * from '../test/generated-wrappers/zrx_token';
|
210
contracts/erc20/test/zrx_token.ts
Normal file
210
contracts/erc20/test/zrx_token.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
96
contracts/erc20/truffle-config.js
Normal file
96
contracts/erc20/truffle-config.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
32
contracts/erc20/tsconfig.json
Normal file
32
contracts/erc20/tsconfig.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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/WETH9V06.json",
|
||||
"test/generated-artifacts/ZRXToken.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
6
contracts/erc20/tslint.json
Normal file
6
contracts/erc20/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false
|
||||
}
|
||||
}
|
7
contracts/erc20/typedoc-tsconfig.json
Normal file
7
contracts/erc20/typedoc-tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"overrides": [],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json",
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"ignorePatterns": [
|
||||
"lib/**/*",
|
||||
"contracts/**/*",
|
||||
"generated-wrappers/**/*",
|
||||
"generated-artifacts/**/*",
|
||||
"test/generated-wrappers/**/*",
|
||||
"test/generated-artifacts/**/*"
|
||||
|
||||
],
|
||||
"rules": {}
|
||||
}
|
@@ -1,194 +1,4 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "5.4.48",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "5.4.47",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675105183,
|
||||
"version": "5.4.46",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1674517560,
|
||||
"version": "5.4.45",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1670879498,
|
||||
"version": "5.4.44",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1669235113,
|
||||
"version": "5.4.43",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1668477029,
|
||||
"version": "5.4.42",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1667607537,
|
||||
"version": "5.4.41",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1667427402,
|
||||
"version": "5.4.40",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1666645023,
|
||||
"version": "5.4.39",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1666381417,
|
||||
"version": "5.4.38",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1665531940,
|
||||
"version": "5.4.37",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "5.4.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Migrate from TSLint to ESLint and fix linting errors",
|
||||
"pr": 589
|
||||
}
|
||||
],
|
||||
"timestamp": 1665013355
|
||||
},
|
||||
{
|
||||
"timestamp": 1663786955,
|
||||
"version": "5.4.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662998180,
|
||||
"version": "5.4.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662559804,
|
||||
"version": "5.4.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662147076,
|
||||
"version": "5.4.32",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662046042,
|
||||
"version": "5.4.31",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661462289,
|
||||
"version": "5.4.30",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661459661,
|
||||
"version": "5.4.29",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661145612,
|
||||
"version": "5.4.28",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1660093941,
|
||||
"version": "5.4.27",
|
||||
|
@@ -5,90 +5,6 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.4.48 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.47 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.46 - _January 30, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.45 - _January 23, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.44 - _December 12, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.43 - _November 23, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.42 - _November 15, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.41 - _November 5, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.40 - _November 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.39 - _October 24, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.38 - _October 21, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.37 - _October 11, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.36 - _October 5, 2022_
|
||||
|
||||
* Migrate from TSLint to ESLint and fix linting errors (#589)
|
||||
|
||||
## v5.4.35 - _September 21, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.34 - _September 12, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.33 - _September 7, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.32 - _September 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.31 - _September 1, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.30 - _August 25, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.29 - _August 25, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.28 - _August 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.27 - _August 10, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -24,7 +24,7 @@ import {
|
||||
|
||||
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.
|
||||
|
||||
Please read our [contribution guidelines](../../.github/CONTRIBUTING.md) before getting started.
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.4.48",
|
||||
"version": "5.4.27",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -13,11 +13,16 @@
|
||||
"build": "tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"test": "yarn run_mocha",
|
||||
"test:coverage": "run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"clean": "shx rm -rf lib",
|
||||
"lint": "eslint src test",
|
||||
"fix": "eslint --fix src test",
|
||||
"test:ci": "yarn test"
|
||||
"lint": "tslint --format stylish --project tsconfig.lint.json",
|
||||
"fix": "tslint --fix --format stylish --project tsconfig.lint.json",
|
||||
"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"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,21 +35,20 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/test-utils",
|
||||
"devDependencies": {
|
||||
"@0x/sol-compiler": "^4.8.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.0",
|
||||
"@typescript-eslint/parser": "^5.38.0",
|
||||
"eslint": "^8.23.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.35",
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"@0x/contract-addresses": "^8.1.0",
|
||||
"@0x/contract-addresses": "^6.19.2",
|
||||
"@0x/dev-utils": "^5.0.0",
|
||||
"@0x/json-schemas": "^6.4.4",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-coverage": "^4.0.46",
|
||||
"@0x/sol-profiler": "^4.1.36",
|
||||
"@0x/sol-trace": "^3.0.46",
|
||||
"@0x/subproviders": "^7.0.0",
|
||||
|
@@ -102,9 +102,9 @@ export async function expectTransactionFailedAsync(p: sendTransactionResult, rea
|
||||
if (nodeType === undefined) {
|
||||
nodeType = await web3Wrapper.getNodeTypeAsync();
|
||||
}
|
||||
const rejectionMessageRegex = new RegExp(`^VM Exception while processing transaction: revert ${reason}$`);
|
||||
switch (nodeType) {
|
||||
case NodeType.Ganache:
|
||||
const rejectionMessageRegex = new RegExp(`^VM Exception while processing transaction: revert ${reason}$`);
|
||||
return expect(p).to.be.rejectedWith(rejectionMessageRegex);
|
||||
case NodeType.Geth:
|
||||
logUtils.warn(
|
||||
|
26
contracts/test-utils/src/coverage.ts
Normal file
26
contracts/test-utils/src/coverage.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { devConstants } from '@0x/dev-utils';
|
||||
import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-coverage';
|
||||
let coverageSubprovider: CoverageSubprovider;
|
||||
|
||||
export const coverage = {
|
||||
getCoverageSubproviderSingleton(): CoverageSubprovider {
|
||||
if (coverageSubprovider === undefined) {
|
||||
coverageSubprovider = coverage._getCoverageSubprovider();
|
||||
}
|
||||
return coverageSubprovider;
|
||||
},
|
||||
_getCoverageSubprovider(): CoverageSubprovider {
|
||||
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
|
||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
|
||||
const coverageSubproviderConfig = {
|
||||
isVerbose: true,
|
||||
ignoreFilesGlobs: ['**/node_modules/**', '**/interfaces/**', '**/test/**'],
|
||||
};
|
||||
const subprovider = new CoverageSubprovider(
|
||||
solCompilerArtifactAdapter,
|
||||
defaultFromAddress,
|
||||
coverageSubproviderConfig,
|
||||
);
|
||||
return subprovider;
|
||||
},
|
||||
};
|
15
contracts/test-utils/src/global_hooks.ts
Normal file
15
contracts/test-utils/src/global_hooks.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { env, EnvVars } from '@0x/dev-utils';
|
||||
|
||||
import { coverage } from './coverage';
|
||||
import { profiler } from './profiler';
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
@@ -20,6 +20,7 @@ export { signingUtils } from './signing_utils';
|
||||
export { orderUtils } from './order_utils';
|
||||
export { typeEncodingUtils } from './type_encoding_utils';
|
||||
export { profiler } from './profiler';
|
||||
export { coverage } from './coverage';
|
||||
export { Web3ProviderEngine } from '@0x/subproviders';
|
||||
export { randomAddress } from './address_utils';
|
||||
export { OrderFactory } from './order_factory';
|
||||
|
@@ -11,14 +11,9 @@ export function shortZip<T1, T2>(a: T1[], b: T2[]): Array<[T1, T2]> {
|
||||
/**
|
||||
* Replaces the keys in a deeply nested object. Adapted from https://stackoverflow.com/a/39126851
|
||||
*/
|
||||
export function replaceKeysDeep(
|
||||
obj: Record<string, unknown>,
|
||||
mapKeys: (key: string) => string | void,
|
||||
): _.Dictionary<Record<string, unknown>> {
|
||||
export function replaceKeysDeep(obj: {}, mapKeys: (key: string) => string | void): _.Dictionary<{}> {
|
||||
return _.transform(obj, (result, value, key) => {
|
||||
const currentKey = mapKeys(key) || key;
|
||||
result[currentKey] = _.isObject(value)
|
||||
? replaceKeysDeep(value as Record<string, unknown>, mapKeys)
|
||||
: (value as Record<string, unknown>);
|
||||
result[currentKey] = _.isObject(value) ? replaceKeysDeep(value as {}, mapKeys) : (value as {});
|
||||
});
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@ export class LogDecoder {
|
||||
}
|
||||
public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||
const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
if ((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args === undefined) {
|
||||
throw new Error(`Unable to decode log: ${JSON.stringify(log)}`);
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ import { LogEntry, LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from
|
||||
|
||||
import { expect } from './chai_setup';
|
||||
|
||||
// tslint:disable no-unnecessary-type-assertion
|
||||
|
||||
/**
|
||||
* Filter logs by event name/type.
|
||||
*/
|
||||
|
@@ -8,6 +8,8 @@ import * as process from 'process';
|
||||
|
||||
import { provider, providerConfigs, txDefaults, web3Wrapper } from './web3_wrapper';
|
||||
|
||||
// tslint:disable: no-namespace only-arrow-functions no-unbound-method max-classes-per-file
|
||||
|
||||
export type ISuite = mocha.ISuite;
|
||||
export type ISuiteCallbackContext = mocha.ISuiteCallbackContext;
|
||||
export type SuiteCallback = (this: ISuiteCallbackContext) => void;
|
||||
@@ -234,7 +236,7 @@ export const describe = _.assign(mochaDescribe, {
|
||||
* Like mocha's `describe()`, but sets up a blockchain environment for you.
|
||||
*/
|
||||
export const blockchainTests: BlockchainContextDefinition = _.assign(
|
||||
function (description: string, callback: BlockchainSuiteCallback): ISuite {
|
||||
function(description: string, callback: BlockchainSuiteCallback): ISuite {
|
||||
return defineBlockchainSuite(StandardBlockchainTestsEnvironmentSingleton, description, callback, describe);
|
||||
},
|
||||
{
|
||||
@@ -273,7 +275,7 @@ export const blockchainTests: BlockchainContextDefinition = _.assign(
|
||||
);
|
||||
},
|
||||
fork: _.assign(
|
||||
function (description: string, callback: BlockchainSuiteCallback): ISuite | void {
|
||||
function(description: string, callback: BlockchainSuiteCallback): ISuite | void {
|
||||
return defineBlockchainSuite(
|
||||
ForkedBlockchainTestsEnvironmentSingleton,
|
||||
description,
|
||||
@@ -317,7 +319,7 @@ export const blockchainTests: BlockchainContextDefinition = _.assign(
|
||||
},
|
||||
),
|
||||
live: _.assign(
|
||||
function (description: string, callback: BlockchainSuiteCallback): ISuite | void {
|
||||
function(description: string, callback: BlockchainSuiteCallback): ISuite | void {
|
||||
return defineBlockchainSuite(
|
||||
LiveBlockchainTestsEnvironmentSingleton,
|
||||
description,
|
||||
@@ -353,7 +355,7 @@ export const blockchainTests: BlockchainContextDefinition = _.assign(
|
||||
},
|
||||
),
|
||||
resets: _.assign(
|
||||
function (description: string, callback: BlockchainSuiteCallback): ISuite {
|
||||
function(description: string, callback: BlockchainSuiteCallback): ISuite {
|
||||
return defineResetsBlockchainSuite(
|
||||
StandardBlockchainTestsEnvironmentSingleton,
|
||||
description,
|
||||
@@ -397,7 +399,7 @@ function defineBlockchainSuite<T>(
|
||||
callback: BlockchainSuiteCallback,
|
||||
describeCall: ContextDefinitionCallback<T>,
|
||||
): T {
|
||||
return describeCall(description, function (this: ISuiteCallbackContext): void {
|
||||
return describeCall(description, function(this: ISuiteCallbackContext): void {
|
||||
callback.call(this, envFactory.create());
|
||||
});
|
||||
}
|
||||
@@ -408,7 +410,7 @@ function defineResetsBlockchainSuite<T>(
|
||||
callback: BlockchainSuiteCallback,
|
||||
describeCall: ContextDefinitionCallback<T>,
|
||||
): T {
|
||||
return describeCall(description, function (this: ISuiteCallbackContext): void {
|
||||
return describeCall(description, function(this: ISuiteCallbackContext): void {
|
||||
const env = envFactory.create();
|
||||
beforeEach(async () => env.blockchainLifecycle.startAsync());
|
||||
afterEach(async () => env.blockchainLifecycle.revertAsync());
|
||||
|
@@ -40,7 +40,10 @@ export function getRandomPortion(total: Numberish): BigNumber {
|
||||
export function getRandomFloat(min: Numberish, max: Numberish): BigNumber {
|
||||
// Generate a really high precision number between [0, 1]
|
||||
const r = new BigNumber(crypto.randomBytes(32).toString('hex'), 16).dividedBy(new BigNumber(2).pow(256).minus(1));
|
||||
return new BigNumber(max).minus(min).times(r).plus(min);
|
||||
return new BigNumber(max)
|
||||
.minus(min)
|
||||
.times(r)
|
||||
.plus(min);
|
||||
}
|
||||
|
||||
export const FIXED_POINT_BASE = new BigNumber(2).pow(127);
|
||||
@@ -63,7 +66,7 @@ export function fromFixed(n: Numberish): BigNumber {
|
||||
* Converts two decimal numbers to integers with `precision` digits, then returns
|
||||
* the absolute difference.
|
||||
*/
|
||||
export function getNumericalDivergence(a: Numberish, b: Numberish, precision = 18): number {
|
||||
export function getNumericalDivergence(a: Numberish, b: Numberish, precision: number = 18): number {
|
||||
const _a = new BigNumber(a);
|
||||
const _b = new BigNumber(b);
|
||||
const maxIntegerDigits = Math.max(
|
||||
@@ -74,13 +77,16 @@ export function getNumericalDivergence(a: Numberish, b: Numberish, precision = 1
|
||||
const base = 10 ** (precision - maxIntegerDigits);
|
||||
return n.times(base).integerValue(BigNumber.ROUND_DOWN);
|
||||
};
|
||||
return _toInteger(_a).minus(_toInteger(_b)).abs().toNumber();
|
||||
return _toInteger(_a)
|
||||
.minus(_toInteger(_b))
|
||||
.abs()
|
||||
.toNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that two numbers are equal up to `precision` digits.
|
||||
*/
|
||||
export function assertRoughlyEquals(actual: Numberish, expected: Numberish, precision = 18): void {
|
||||
export function assertRoughlyEquals(actual: Numberish, expected: Numberish, precision: number = 18): void {
|
||||
if (getNumericalDivergence(actual, expected, precision) <= 1) {
|
||||
return;
|
||||
}
|
||||
@@ -90,8 +96,16 @@ export function assertRoughlyEquals(actual: Numberish, expected: Numberish, prec
|
||||
/**
|
||||
* Asserts that two numbers are equal with up to `maxError` difference between them.
|
||||
*/
|
||||
export function assertIntegerRoughlyEquals(actual: Numberish, expected: Numberish, maxError = 1, msg?: string): void {
|
||||
const diff = new BigNumber(actual).minus(expected).abs().toNumber();
|
||||
export function assertIntegerRoughlyEquals(
|
||||
actual: Numberish,
|
||||
expected: Numberish,
|
||||
maxError: number = 1,
|
||||
msg?: string,
|
||||
): void {
|
||||
const diff = new BigNumber(actual)
|
||||
.minus(expected)
|
||||
.abs()
|
||||
.toNumber();
|
||||
if (diff <= maxError) {
|
||||
return;
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ export class OrderFactory {
|
||||
salt: generatePseudoRandomSalt(),
|
||||
...this._defaultOrderParams,
|
||||
...customOrderParams,
|
||||
} as Order;
|
||||
} as Order; // tslint:disable-line:no-object-literal-type-assertion
|
||||
const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
|
||||
const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType);
|
||||
const signedOrder = {
|
||||
|
@@ -8,7 +8,10 @@ import { BatchMatchOrder, CancelOrder, MatchOrder } from './types';
|
||||
|
||||
export const orderUtils = {
|
||||
getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
const partialAmount = numerator.multipliedBy(target).div(denominator).integerValue(BigNumber.ROUND_FLOOR);
|
||||
const partialAmount = numerator
|
||||
.multipliedBy(target)
|
||||
.div(denominator)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return partialAmount;
|
||||
},
|
||||
createFill: (signedOrder: SignedOrder, takerAssetFillAmount?: BigNumber) => {
|
||||
|
@@ -9,6 +9,7 @@ export const typeEncodingUtils = {
|
||||
const base = 10;
|
||||
const formattedValue = new BN(value.toString(base));
|
||||
const encodedValue = ethUtil.toBuffer(formattedValue);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const paddedValue = ethUtil.setLengthLeft(encodedValue, constants.WORD_LENGTH);
|
||||
return paddedValue;
|
||||
},
|
||||
|
@@ -90,6 +90,7 @@ export enum ContractName {
|
||||
DummyERC721Token = 'DummyERC721Token',
|
||||
TestLibBytes = 'TestLibBytes',
|
||||
TestWallet = 'TestWallet',
|
||||
Authorizable = 'Authorizable',
|
||||
Whitelist = 'Whitelist',
|
||||
Forwarder = 'Forwarder',
|
||||
BalanceThresholdFilter = 'BalanceThresholdFilter',
|
||||
|
@@ -5,6 +5,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { coverage } from './coverage';
|
||||
import { profiler } from './profiler';
|
||||
import { revertTrace } from './revert_trace';
|
||||
|
||||
@@ -14,7 +15,7 @@ export const txDefaults = {
|
||||
gasPrice: constants.DEFAULT_GAS_PRICE,
|
||||
};
|
||||
|
||||
export const providerConfigs: Web3Config = {
|
||||
export let providerConfigs: Web3Config = {
|
||||
total_accounts: constants.NUM_TEST_ACCOUNTS,
|
||||
shouldUseInProcessGanache: true,
|
||||
shouldAllowUnlimitedContractSize: true,
|
||||
@@ -38,7 +39,11 @@ const enabledSubproviderCount = _.filter(
|
||||
_.identity.bind(_),
|
||||
).length;
|
||||
if (enabledSubproviderCount > 1) {
|
||||
throw new Error(`Only one of profiler or revert trace subproviders can be enabled at a time`);
|
||||
throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`);
|
||||
}
|
||||
if (isCoverageEnabled) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
prependSubprovider(provider, coverageSubprovider);
|
||||
}
|
||||
if (isProfilerEnabled) {
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
|
@@ -4,7 +4,6 @@ import * as process from 'process';
|
||||
import { expect } from '../src/chai_setup';
|
||||
import { constants } from '../src/constants';
|
||||
import { blockchainTests, describe } from '../src/mocha_blockchain';
|
||||
import { append } from './subtests/mocha_blockchain_1';
|
||||
|
||||
blockchainTests('mocha blockchain extensions', env => {
|
||||
describe('blockchainTests()', () => {
|
||||
@@ -13,8 +12,11 @@ blockchainTests('mocha blockchain extensions', env => {
|
||||
expect(env.provider).to.exist('');
|
||||
expect(env.txDefaults).to.exist('');
|
||||
expect(env.web3Wrapper).to.exist('');
|
||||
// HACK(dorothy-zbornak): tslint seems to get confused by these assertions.
|
||||
// tslint:disable: no-unbound-method
|
||||
expect(typeof env.getChainIdAsync).to.eq('function');
|
||||
expect(typeof env.getAccountAddressesAsync).to.eq('function');
|
||||
// tslint:enable: no-unbound-method
|
||||
});
|
||||
|
||||
it('initializes the test environment', async () => {
|
||||
@@ -76,7 +78,7 @@ blockchainTests('mocha blockchain extensions', env => {
|
||||
});
|
||||
|
||||
describe('subtests', () => {
|
||||
append(env);
|
||||
require('./subtests/mocha_blockchain_1').append(env);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -93,7 +95,8 @@ blockchainTests('mocha blockchain extensions', env => {
|
||||
|
||||
function createHookedObject(obj: any, handler: (name: string) => void, methods: string[]): any {
|
||||
const hookedMethods = _.map(methods, methodName => {
|
||||
return function (this: any, ...args: any[]): any {
|
||||
// tslint:disable: only-arrow-functions
|
||||
return function(this: any, ...args: any[]): any {
|
||||
handler(methodName);
|
||||
return obj[methodName].call(this, ...args);
|
||||
};
|
||||
|
@@ -42,6 +42,7 @@ describe('Order hashing', () => {
|
||||
// It's common for developers using javascript to provide the amounts
|
||||
// as strings. Since we eventually toString() the BigNumber
|
||||
// before encoding we should result in the same orderHash in this scenario
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const orderHash = orderHashUtils.getOrderHashHex({
|
||||
...order,
|
||||
makerAssetAmount: '0',
|
||||
@@ -54,7 +55,7 @@ describe('Order hashing', () => {
|
||||
it('throws a readable error message if taker format is invalid', async () => {
|
||||
const orderWithInvalidtakerFormat = {
|
||||
...order,
|
||||
takerAddress: null as any as string,
|
||||
takerAddress: (null as any) as string,
|
||||
};
|
||||
const expectedErrorMessage = `Expected order to conform to schema`;
|
||||
expect(() => orderHashUtils.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { expect } from '../../src/chai_setup';
|
||||
import { blockchainTests, BlockchainTestsEnvironment } from '../../src/mocha_blockchain';
|
||||
|
||||
// tslint:disable: no-default-export completed-docs
|
||||
export function append(env: BlockchainTestsEnvironment): void {
|
||||
blockchainTests('imported subtests', subtestsEnv => {
|
||||
it('shares the same environment object', () => {
|
||||
|
@@ -35,6 +35,7 @@ describe('0x transaction hashing', () => {
|
||||
// It's common for developers using javascript to provide the amounts
|
||||
// as strings. Since we eventually toString() the BigNumber
|
||||
// before encoding we should result in the same orderHash in this scenario
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex({
|
||||
...transaction,
|
||||
salt: '0',
|
||||
|
7
contracts/test-utils/tsconfig.lint.json
Normal file
7
contracts/test-utils/tsconfig.lint.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
// This file is a workaround that issue: https://github.com/palantir/tslint/issues/4148#issuecomment-419872702
|
||||
"extends": "./tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": false
|
||||
}
|
||||
}
|
6
contracts/test-utils/tslint.json
Normal file
6
contracts/test-utils/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"overrides": [],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json",
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"ignorePatterns": [
|
||||
"lib/**/*",
|
||||
"contracts/**/*",
|
||||
"generated-wrappers/**/*",
|
||||
"generated-artifacts/**/*",
|
||||
"test/generated-wrappers/**/*",
|
||||
"test/generated-artifacts/**/*"
|
||||
|
||||
],
|
||||
"rules": {}
|
||||
}
|
@@ -1,203 +1,4 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1677693479,
|
||||
"version": "1.4.41",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675210931,
|
||||
"version": "1.4.40",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1675105183,
|
||||
"version": "1.4.39",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1674517560,
|
||||
"version": "1.4.38",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1670879498,
|
||||
"version": "1.4.37",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1669235113,
|
||||
"version": "1.4.36",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1668477029,
|
||||
"version": "1.4.35",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1667607537,
|
||||
"version": "1.4.34",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1667427402,
|
||||
"version": "1.4.33",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1666645023,
|
||||
"version": "1.4.32",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1666381417,
|
||||
"version": "1.4.31",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1665670315,
|
||||
"version": "1.4.30",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1665531940,
|
||||
"version": "1.4.29",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.28",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Migrate from TSLint to ESLint and fix linting errors",
|
||||
"pr": 589
|
||||
}
|
||||
],
|
||||
"timestamp": 1665013355
|
||||
},
|
||||
{
|
||||
"timestamp": 1663786955,
|
||||
"version": "1.4.27",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662998180,
|
||||
"version": "1.4.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662559804,
|
||||
"version": "1.4.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662147076,
|
||||
"version": "1.4.24",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1662046042,
|
||||
"version": "1.4.23",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661462289,
|
||||
"version": "1.4.22",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661459661,
|
||||
"version": "1.4.21",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1661145612,
|
||||
"version": "1.4.20",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1660093941,
|
||||
"version": "1.4.19",
|
||||
|
@@ -5,94 +5,6 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.4.41 - _March 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.40 - _February 1, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.39 - _January 30, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.38 - _January 23, 2023_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.37 - _December 12, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.36 - _November 23, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.35 - _November 15, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.34 - _November 5, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.33 - _November 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.32 - _October 24, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.31 - _October 21, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.30 - _October 13, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.29 - _October 11, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.28 - _October 5, 2022_
|
||||
|
||||
* Migrate from TSLint to ESLint and fix linting errors (#589)
|
||||
|
||||
## v1.4.27 - _September 21, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.26 - _September 12, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.25 - _September 7, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.24 - _September 2, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.23 - _September 1, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.22 - _August 25, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.21 - _August 25, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.20 - _August 22, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.19 - _August 10, 2022_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -16,7 +16,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](../../.github/CONTRIBUTING.md) before getting started.
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
|
@@ -36,9 +36,7 @@ interface ISablier {
|
||||
|
||||
function balanceOf(uint256 streamId, address who) external view returns (uint256 balance);
|
||||
|
||||
function getStream(
|
||||
uint256 streamId
|
||||
)
|
||||
function getStream(uint256 streamId)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
@@ -52,15 +50,11 @@ interface ISablier {
|
||||
uint256 ratePerSecond
|
||||
);
|
||||
|
||||
function createStream(
|
||||
address recipient,
|
||||
uint256 deposit,
|
||||
address tokenAddress,
|
||||
uint256 startTime,
|
||||
uint256 stopTime
|
||||
) external returns (uint256 streamId);
|
||||
function createStream(address recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime)
|
||||
external
|
||||
returns (uint256 streamId);
|
||||
|
||||
function withdrawFromStream(uint256 streamId, uint256 funds) external returns (bool);
|
||||
|
||||
function cancelStream(uint256 streamId) external returns (bool);
|
||||
}
|
||||
}
|
@@ -20,19 +20,25 @@
|
||||
pragma solidity ^0.6.12;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/src/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./IStaking.sol";
|
||||
|
||||
|
||||
contract DefaultPoolOperator {
|
||||
// Immutables
|
||||
IStaking public immutable stakingProxy;
|
||||
IERC20Token public immutable weth;
|
||||
IERC20TokenV06 public immutable weth;
|
||||
bytes32 public immutable poolId;
|
||||
|
||||
/// @dev Initializes this contract and creates a staking pool.
|
||||
/// @param stakingProxy_ The 0x staking proxy contract.
|
||||
/// @param weth_ The WETH token contract.
|
||||
constructor(IStaking stakingProxy_, IERC20Token weth_) public {
|
||||
constructor(
|
||||
IStaking stakingProxy_,
|
||||
IERC20TokenV06 weth_
|
||||
)
|
||||
public
|
||||
{
|
||||
stakingProxy = stakingProxy_;
|
||||
weth = weth_;
|
||||
// operator share = 100%
|
||||
@@ -45,7 +51,9 @@ contract DefaultPoolOperator {
|
||||
/// market making for some reason, thus earning this contract
|
||||
/// some staking rewards. Note that anyone can call this
|
||||
/// function at any time.
|
||||
function returnStakingRewards() external {
|
||||
function returnStakingRewards()
|
||||
external
|
||||
{
|
||||
uint256 wethBalance = weth.balanceOf(address(this));
|
||||
weth.transfer(address(stakingProxy), wethBalance);
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
pragma solidity ^0.6.12;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
interface IStaking {
|
||||
/// @dev Statuses that stake can exist in.
|
||||
/// Any stake can be (re)delegated effective at the next epoch
|
||||
@@ -54,28 +55,45 @@ interface IStaking {
|
||||
/// @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);
|
||||
function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker)
|
||||
external
|
||||
returns (bytes32 poolId);
|
||||
|
||||
/// @dev Returns the current staking epoch number.
|
||||
/// @return epoch The current epoch.
|
||||
function currentEpoch() external view returns (uint256 epoch);
|
||||
function currentEpoch()
|
||||
external
|
||||
view
|
||||
returns (uint256 epoch);
|
||||
|
||||
/// @dev Returns the time (in seconds) at which the current staking epoch started.
|
||||
/// @return startTime The start time of the current epoch, in seconds.
|
||||
function currentEpochStartTimeInSeconds() external view returns (uint256 startTime);
|
||||
function currentEpochStartTimeInSeconds()
|
||||
external
|
||||
view
|
||||
returns (uint256 startTime);
|
||||
|
||||
/// @dev Returns the duration of an epoch in seconds. This value can be updated.
|
||||
/// @return duration The duration of an epoch, in seconds.
|
||||
function epochDurationInSeconds() external view returns (uint256 duration);
|
||||
function epochDurationInSeconds()
|
||||
external
|
||||
view
|
||||
returns (uint256 duration);
|
||||
|
||||
/// @dev Returns a staking pool
|
||||
/// @param poolId Unique id of pool.
|
||||
function getStakingPool(bytes32 poolId) external view returns (Pool memory);
|
||||
function getStakingPool(bytes32 poolId)
|
||||
external
|
||||
view
|
||||
returns (Pool memory);
|
||||
|
||||
/// @dev Gets global stake for a given status.
|
||||
/// @param stakeStatus UNDELEGATED or DELEGATED
|
||||
/// @return balance Global stake for given status.
|
||||
function getGlobalStakeByStatus(StakeStatus stakeStatus) external view returns (StoredBalance memory balance);
|
||||
function getGlobalStakeByStatus(StakeStatus stakeStatus)
|
||||
external
|
||||
view
|
||||
returns (StoredBalance memory balance);
|
||||
|
||||
/// @dev Gets an owner's stake balances by status.
|
||||
/// @param staker Owner of stake.
|
||||
@@ -84,20 +102,26 @@ interface IStaking {
|
||||
function getOwnerStakeByStatus(
|
||||
address staker,
|
||||
StakeStatus stakeStatus
|
||||
) external view returns (StoredBalance memory balance);
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (StoredBalance memory balance);
|
||||
|
||||
/// @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 (StoredBalance memory balance);
|
||||
function getTotalStakeDelegatedToPool(bytes32 poolId)
|
||||
external
|
||||
view
|
||||
returns (StoredBalance memory balance);
|
||||
|
||||
/// @dev Returns the stake delegated to a specific staking pool, by a given staker.
|
||||
/// @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 (StoredBalance memory balance);
|
||||
function getStakeDelegatedToPoolByOwner(address staker, bytes32 poolId)
|
||||
external
|
||||
view
|
||||
returns (StoredBalance memory balance);
|
||||
}
|
||||
|
@@ -23,7 +23,9 @@ pragma experimental ABIEncoderV2;
|
||||
import "./DefaultPoolOperator.sol";
|
||||
import "./IStaking.sol";
|
||||
|
||||
|
||||
interface IZrxTreasury {
|
||||
|
||||
struct TreasuryParameters {
|
||||
uint256 votingPeriod;
|
||||
uint256 proposalThreshold;
|
||||
@@ -55,21 +57,45 @@ interface IZrxTreasury {
|
||||
string description
|
||||
);
|
||||
|
||||
event VoteCast(address voter, bytes32[] operatedPoolIds, uint256 proposalId, bool support, uint256 votingPower);
|
||||
event VoteCast(
|
||||
address voter,
|
||||
bytes32[] operatedPoolIds,
|
||||
uint256 proposalId,
|
||||
bool support,
|
||||
uint256 votingPower
|
||||
);
|
||||
|
||||
event ProposalExecuted(uint256 proposalId);
|
||||
|
||||
function stakingProxy() external view returns (IStaking);
|
||||
function stakingProxy()
|
||||
external
|
||||
view
|
||||
returns (IStaking);
|
||||
|
||||
function defaultPoolOperator() external view returns (DefaultPoolOperator);
|
||||
function defaultPoolOperator()
|
||||
external
|
||||
view
|
||||
returns (DefaultPoolOperator);
|
||||
|
||||
function defaultPoolId() external view returns (bytes32);
|
||||
function defaultPoolId()
|
||||
external
|
||||
view
|
||||
returns (bytes32);
|
||||
|
||||
function votingPeriod() external view returns (uint256);
|
||||
function votingPeriod()
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
function proposalThreshold() external view returns (uint256);
|
||||
function proposalThreshold()
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
function quorumThreshold() 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
|
||||
@@ -77,7 +103,11 @@ interface IZrxTreasury {
|
||||
/// 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;
|
||||
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`
|
||||
@@ -101,7 +131,9 @@ interface IZrxTreasury {
|
||||
uint256 executionEpoch,
|
||||
string calldata description,
|
||||
bytes32[] calldata operatedPoolIds
|
||||
) external returns (uint256 proposalId);
|
||||
)
|
||||
external
|
||||
returns (uint256 proposalId);
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
/// during the voting period for that proposal.
|
||||
@@ -112,7 +144,12 @@ interface IZrxTreasury {
|
||||
/// @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;
|
||||
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.
|
||||
@@ -133,17 +170,23 @@ interface IZrxTreasury {
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) external;
|
||||
)
|
||||
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;
|
||||
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);
|
||||
function proposalCount()
|
||||
external
|
||||
view
|
||||
returns (uint256 count);
|
||||
|
||||
/// @dev Computes the current voting power of the given account.
|
||||
/// Voting power is equal to:
|
||||
@@ -155,8 +198,8 @@ interface IZrxTreasury {
|
||||
/// 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);
|
||||
function getVotingPower(address account, bytes32[] calldata operatedPoolIds)
|
||||
external
|
||||
view
|
||||
returns (uint256 votingPower);
|
||||
}
|
||||
|
@@ -26,7 +26,10 @@ import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/features/libs/LibSignature.sol";
|
||||
import "./IZrxTreasury.sol";
|
||||
|
||||
contract ZrxTreasury is IZrxTreasury {
|
||||
|
||||
contract ZrxTreasury is
|
||||
IZrxTreasury
|
||||
{
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
using LibBytesV06 for bytes;
|
||||
@@ -38,12 +41,10 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
string private constant CONTRACT_VERSION = "1.0.0";
|
||||
|
||||
/// The EIP-712 typehash for the contract's domain
|
||||
bytes32 private constant DOMAIN_TYPEHASH =
|
||||
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
|
||||
bytes32 private constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
|
||||
|
||||
/// The EIP-712 typehash for the vote struct
|
||||
bytes32 private constant VOTE_TYPEHASH =
|
||||
keccak256("TreasuryVote(uint256 proposalId,bool support,bytes32[] operatedPoolIds)");
|
||||
bytes32 private constant VOTE_TYPEHASH = keccak256("TreasuryVote(uint256 proposalId,bool support,bytes32[] operatedPoolIds)");
|
||||
|
||||
// Immutables
|
||||
IStaking public immutable override stakingProxy;
|
||||
@@ -57,14 +58,22 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
|
||||
// Storage
|
||||
Proposal[] public proposals;
|
||||
mapping(uint256 => mapping(address => bool)) public hasVoted;
|
||||
mapping (uint256 => mapping (address => bool)) public hasVoted;
|
||||
|
||||
/// @dev Initializes the ZRX treasury and creates the default
|
||||
/// staking pool.
|
||||
/// @param stakingProxy_ The 0x staking proxy contract.
|
||||
/// @param params Immutable treasury parameters.
|
||||
constructor(IStaking stakingProxy_, TreasuryParameters memory params) public {
|
||||
require(params.votingPeriod < stakingProxy_.epochDurationInSeconds(), "VOTING_PERIOD_TOO_LONG");
|
||||
constructor(
|
||||
IStaking stakingProxy_,
|
||||
TreasuryParameters memory params
|
||||
)
|
||||
public
|
||||
{
|
||||
require(
|
||||
params.votingPeriod < stakingProxy_.epochDurationInSeconds(),
|
||||
"VOTING_PERIOD_TOO_LONG"
|
||||
);
|
||||
stakingProxy = stakingProxy_;
|
||||
votingPeriod = params.votingPeriod;
|
||||
proposalThreshold = params.proposalThreshold;
|
||||
@@ -83,8 +92,10 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
);
|
||||
}
|
||||
|
||||
// solhint-disable
|
||||
/// @dev Allows this contract to receive ether.
|
||||
receive() external payable {}
|
||||
// solhint-enable
|
||||
|
||||
/// @dev Updates the proposal and quorum thresholds to the given
|
||||
/// values. Note that this function is only callable by the
|
||||
@@ -92,7 +103,13 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// 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 override {
|
||||
function updateThresholds(
|
||||
uint256 newProposalThreshold,
|
||||
uint256 newQuorumThreshold
|
||||
)
|
||||
external
|
||||
override
|
||||
{
|
||||
require(msg.sender == address(this), "updateThresholds/ONLY_SELF");
|
||||
proposalThreshold = newProposalThreshold;
|
||||
quorumThreshold = newQuorumThreshold;
|
||||
@@ -120,11 +137,24 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
uint256 executionEpoch,
|
||||
string memory description,
|
||||
bytes32[] memory operatedPoolIds
|
||||
) public override returns (uint256 proposalId) {
|
||||
require(getVotingPower(msg.sender, operatedPoolIds) >= proposalThreshold, "propose/INSUFFICIENT_VOTING_POWER");
|
||||
require(actions.length > 0, "propose/NO_ACTIONS_PROPOSED");
|
||||
)
|
||||
public
|
||||
override
|
||||
returns (uint256 proposalId)
|
||||
{
|
||||
require(
|
||||
getVotingPower(msg.sender, operatedPoolIds) >= proposalThreshold,
|
||||
"propose/INSUFFICIENT_VOTING_POWER"
|
||||
);
|
||||
require(
|
||||
actions.length > 0,
|
||||
"propose/NO_ACTIONS_PROPOSED"
|
||||
);
|
||||
uint256 currentEpoch = stakingProxy.currentEpoch();
|
||||
require(executionEpoch >= currentEpoch + 2, "propose/INVALID_EXECUTION_EPOCH");
|
||||
require(
|
||||
executionEpoch >= currentEpoch + 2,
|
||||
"propose/INVALID_EXECUTION_EPOCH"
|
||||
);
|
||||
|
||||
proposalId = proposalCount();
|
||||
Proposal storage newProposal = proposals.push();
|
||||
@@ -132,7 +162,14 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
newProposal.executionEpoch = executionEpoch;
|
||||
newProposal.voteEpoch = currentEpoch + 2;
|
||||
|
||||
emit ProposalCreated(msg.sender, operatedPoolIds, proposalId, actions, executionEpoch, description);
|
||||
emit ProposalCreated(
|
||||
msg.sender,
|
||||
operatedPoolIds,
|
||||
proposalId,
|
||||
actions,
|
||||
executionEpoch,
|
||||
description
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
@@ -144,7 +181,14 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// @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[] memory operatedPoolIds) public override {
|
||||
function castVote(
|
||||
uint256 proposalId,
|
||||
bool support,
|
||||
bytes32[] memory operatedPoolIds
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
return _castVote(msg.sender, proposalId, support, operatedPoolIds);
|
||||
}
|
||||
|
||||
@@ -167,7 +211,10 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) public override {
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
bytes32 structHash = keccak256(
|
||||
abi.encode(VOTE_TYPEHASH, proposalId, support, keccak256(abi.encodePacked(operatedPoolIds)))
|
||||
);
|
||||
@@ -181,7 +228,11 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// 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) public payable override {
|
||||
function execute(uint256 proposalId, ProposedAction[] memory actions)
|
||||
public
|
||||
payable
|
||||
override
|
||||
{
|
||||
if (proposalId >= proposalCount()) {
|
||||
revert("execute/INVALID_PROPOSAL_ID");
|
||||
}
|
||||
@@ -193,7 +244,10 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
for (uint256 i = 0; i != actions.length; i++) {
|
||||
ProposedAction memory action = actions[i];
|
||||
(bool didSucceed, ) = action.target.call{value: action.value}(action.data);
|
||||
require(didSucceed, "execute/ACTION_EXECUTION_FAILED");
|
||||
require(
|
||||
didSucceed,
|
||||
"execute/ACTION_EXECUTION_FAILED"
|
||||
);
|
||||
}
|
||||
|
||||
emit ProposalExecuted(proposalId);
|
||||
@@ -201,7 +255,12 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
|
||||
/// @dev Returns the total number of proposals.
|
||||
/// @return count The number of proposals.
|
||||
function proposalCount() public view override returns (uint256 count) {
|
||||
function proposalCount()
|
||||
public
|
||||
override
|
||||
view
|
||||
returns (uint256 count)
|
||||
{
|
||||
return proposals.length;
|
||||
}
|
||||
|
||||
@@ -215,29 +274,41 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// 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[] memory operatedPoolIds
|
||||
) public view override returns (uint256 votingPower) {
|
||||
uint256 delegatedBalance = stakingProxy
|
||||
.getOwnerStakeByStatus(account, IStaking.StakeStatus.DELEGATED)
|
||||
.currentEpochBalance;
|
||||
uint256 balanceDelegatedToDefaultPool = stakingProxy
|
||||
.getStakeDelegatedToPoolByOwner(account, defaultPoolId)
|
||||
.currentEpochBalance;
|
||||
function getVotingPower(address account, bytes32[] memory operatedPoolIds)
|
||||
public
|
||||
override
|
||||
view
|
||||
returns (uint256 votingPower)
|
||||
{
|
||||
uint256 delegatedBalance = stakingProxy.getOwnerStakeByStatus(
|
||||
account,
|
||||
IStaking.StakeStatus.DELEGATED
|
||||
).currentEpochBalance;
|
||||
uint256 balanceDelegatedToDefaultPool = stakingProxy.getStakeDelegatedToPoolByOwner(
|
||||
account,
|
||||
defaultPoolId
|
||||
).currentEpochBalance;
|
||||
|
||||
// Voting power for ZRX delegated to the default pool is not diluted,
|
||||
// so we double-count the balance delegated to the default pool before
|
||||
// dividing by 2.
|
||||
votingPower = delegatedBalance.safeAdd(balanceDelegatedToDefaultPool).safeDiv(2);
|
||||
votingPower = delegatedBalance
|
||||
.safeAdd(balanceDelegatedToDefaultPool)
|
||||
.safeDiv(2);
|
||||
|
||||
// Add voting power for operated staking pools.
|
||||
for (uint256 i = 0; i != operatedPoolIds.length; i++) {
|
||||
for (uint256 j = 0; j != i; j++) {
|
||||
require(operatedPoolIds[i] != operatedPoolIds[j], "getVotingPower/DUPLICATE_POOL_ID");
|
||||
require(
|
||||
operatedPoolIds[i] != operatedPoolIds[j],
|
||||
"getVotingPower/DUPLICATE_POOL_ID"
|
||||
);
|
||||
}
|
||||
IStaking.Pool memory pool = stakingProxy.getStakingPool(operatedPoolIds[i]);
|
||||
require(pool.operator == account, "getVotingPower/POOL_NOT_OPERATED_BY_ACCOUNT");
|
||||
require(
|
||||
pool.operator == account,
|
||||
"getVotingPower/POOL_NOT_OPERATED_BY_ACCOUNT"
|
||||
);
|
||||
uint96 stakeDelegatedToPool = stakingProxy
|
||||
.getTotalStakeDelegatedToPool(operatedPoolIds[i])
|
||||
.currentEpochBalance;
|
||||
@@ -251,10 +322,25 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// @dev Checks whether the given proposal is executable.
|
||||
/// Reverts if not.
|
||||
/// @param proposal The proposal to check.
|
||||
function _assertProposalExecutable(Proposal memory proposal, ProposedAction[] memory actions) private view {
|
||||
require(keccak256(abi.encode(actions)) == proposal.actionsHash, "_assertProposalExecutable/INVALID_ACTIONS");
|
||||
require(_hasProposalPassed(proposal), "_assertProposalExecutable/PROPOSAL_HAS_NOT_PASSED");
|
||||
require(!proposal.executed, "_assertProposalExecutable/PROPOSAL_ALREADY_EXECUTED");
|
||||
function _assertProposalExecutable(
|
||||
Proposal memory proposal,
|
||||
ProposedAction[] memory actions
|
||||
)
|
||||
private
|
||||
view
|
||||
{
|
||||
require(
|
||||
keccak256(abi.encode(actions)) == proposal.actionsHash,
|
||||
"_assertProposalExecutable/INVALID_ACTIONS"
|
||||
);
|
||||
require(
|
||||
_hasProposalPassed(proposal),
|
||||
"_assertProposalExecutable/PROPOSAL_HAS_NOT_PASSED"
|
||||
);
|
||||
require(
|
||||
!proposal.executed,
|
||||
"_assertProposalExecutable/PROPOSAL_ALREADY_EXECUTED"
|
||||
);
|
||||
require(
|
||||
stakingProxy.currentEpoch() == proposal.executionEpoch,
|
||||
"_assertProposalExecutable/CANNOT_EXECUTE_THIS_EPOCH"
|
||||
@@ -264,7 +350,11 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// @dev Checks whether the given proposal has passed or not.
|
||||
/// @param proposal The proposal to check.
|
||||
/// @return hasPassed Whether the proposal has passed.
|
||||
function _hasProposalPassed(Proposal memory proposal) private view returns (bool hasPassed) {
|
||||
function _hasProposalPassed(Proposal memory proposal)
|
||||
private
|
||||
view
|
||||
returns (bool hasPassed)
|
||||
{
|
||||
// Proposal is not passed until the vote is over.
|
||||
if (!_hasVoteEnded(proposal.voteEpoch)) {
|
||||
return false;
|
||||
@@ -284,7 +374,11 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
/// epoch has ended or not.
|
||||
/// @param voteEpoch The epoch at which the vote started.
|
||||
/// @return hasEnded Whether the vote has ended.
|
||||
function _hasVoteEnded(uint256 voteEpoch) private view returns (bool hasEnded) {
|
||||
function _hasVoteEnded(uint256 voteEpoch)
|
||||
private
|
||||
view
|
||||
returns (bool hasEnded)
|
||||
{
|
||||
uint256 currentEpoch = stakingProxy.currentEpoch();
|
||||
if (currentEpoch < voteEpoch) {
|
||||
return false;
|
||||
@@ -294,14 +388,23 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
}
|
||||
// voteEpoch == currentEpoch
|
||||
// Vote ends at currentEpochStartTime + votingPeriod
|
||||
uint256 voteEndTime = stakingProxy.currentEpochStartTimeInSeconds().safeAdd(votingPeriod);
|
||||
uint256 voteEndTime = stakingProxy
|
||||
.currentEpochStartTimeInSeconds()
|
||||
.safeAdd(votingPeriod);
|
||||
return block.timestamp > voteEndTime;
|
||||
}
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
/// during the voting period for that proposal. See
|
||||
/// `getVotingPower` for how voting power is computed.
|
||||
function _castVote(address voter, uint256 proposalId, bool support, bytes32[] memory operatedPoolIds) private {
|
||||
function _castVote(
|
||||
address voter,
|
||||
uint256 proposalId,
|
||||
bool support,
|
||||
bytes32[] memory operatedPoolIds
|
||||
)
|
||||
private
|
||||
{
|
||||
if (proposalId >= proposalCount()) {
|
||||
revert("_castVote/INVALID_PROPOSAL_ID");
|
||||
}
|
||||
@@ -310,7 +413,10 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
}
|
||||
|
||||
Proposal memory proposal = proposals[proposalId];
|
||||
if (proposal.voteEpoch != stakingProxy.currentEpoch() || _hasVoteEnded(proposal.voteEpoch)) {
|
||||
if (
|
||||
proposal.voteEpoch != stakingProxy.currentEpoch() ||
|
||||
_hasVoteEnded(proposal.voteEpoch)
|
||||
) {
|
||||
revert("_castVote/VOTING_IS_CLOSED");
|
||||
}
|
||||
|
||||
@@ -320,21 +426,27 @@ contract ZrxTreasury is IZrxTreasury {
|
||||
}
|
||||
|
||||
if (support) {
|
||||
proposals[proposalId].votesFor = proposals[proposalId].votesFor.safeAdd(votingPower);
|
||||
proposals[proposalId].votesFor = proposals[proposalId].votesFor
|
||||
.safeAdd(votingPower);
|
||||
} else {
|
||||
proposals[proposalId].votesAgainst = proposals[proposalId].votesAgainst.safeAdd(votingPower);
|
||||
proposals[proposalId].votesAgainst = proposals[proposalId].votesAgainst
|
||||
.safeAdd(votingPower);
|
||||
}
|
||||
hasVoted[proposalId][voter] = true;
|
||||
|
||||
emit VoteCast(voter, operatedPoolIds, proposalId, support, votingPower);
|
||||
emit VoteCast(
|
||||
voter,
|
||||
operatedPoolIds,
|
||||
proposalId,
|
||||
support,
|
||||
votingPower
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Gets the Ethereum chain id
|
||||
function _getChainId() private pure returns (uint256) {
|
||||
uint256 chainId;
|
||||
assembly {
|
||||
chainId := chainid()
|
||||
}
|
||||
assembly { chainId := chainid() }
|
||||
return chainId;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.4.41",
|
||||
"version": "1.4.19",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -21,11 +21,12 @@
|
||||
"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": "eslint src test",
|
||||
"fix": "eslint --fix src test",
|
||||
"test:ci": "yarn test",
|
||||
"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 ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"lint-contracts": "#solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"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",
|
||||
"publish:private": "yarn build && gitpkg publish"
|
||||
@@ -46,34 +47,33 @@
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.8.1",
|
||||
"@0x/contract-addresses": "^8.1.0",
|
||||
"@0x/contract-addresses": "^6.19.2",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-erc20": "3.3.57",
|
||||
"@0x/contracts-gen": "^2.0.48",
|
||||
"@0x/contracts-erc20": "^3.3.36",
|
||||
"@0x/contracts-gen": "^2.0.47",
|
||||
"@0x/contracts-staking": "^2.0.45",
|
||||
"@0x/contracts-test-utils": "^5.4.48",
|
||||
"@0x/contracts-test-utils": "^5.4.27",
|
||||
"@0x/sol-compiler": "^4.8.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/prompts": "^2.0.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.38.0",
|
||||
"@typescript-eslint/parser": "^5.38.0",
|
||||
"eslint": "^8.23.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash": "^4.17.11",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prompts": "^2.4.0",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^7.0.0",
|
||||
"@0x/protocol-utils": "^11.18.0",
|
||||
"@0x/protocol-utils": "^11.16.3",
|
||||
"@0x/subproviders": "^7.0.0",
|
||||
"@0x/types": "^3.3.6",
|
||||
"@0x/typescript-typings": "^5.3.1",
|
||||
|
13
contracts/treasury/tslint.json
Normal file
13
contracts/treasury/tslint.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false,
|
||||
"max-file-line-count": false,
|
||||
"no-non-null-assertion": false,
|
||||
"no-unnecessary-type-assertion": false,
|
||||
"number-literal-format": false
|
||||
},
|
||||
"linterOptions": {
|
||||
"exclude": ["src/artifacts.ts", "test/artifacts.ts"]
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"overrides": [],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json",
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"ignorePatterns": [
|
||||
"lib/**/*",
|
||||
"contracts/**/*",
|
||||
"generated-wrappers/**/*",
|
||||
"generated-artifacts/**/*",
|
||||
"test/generated-wrappers/**/*",
|
||||
"test/generated-artifacts/**/*"
|
||||
|
||||
],
|
||||
"rules": {}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user