Compare commits

..

22 Commits

Author SHA1 Message Date
Duncan Townsend
ac563f5164
Zero out missing UniswapV2 on Polygon 2023-04-10 12:08:56 -04:00
Patrick Dowell
ca7393641f Deploy script for MTX V2 and multiplex 2023-04-10 03:55:09 -07:00
Patrick Dowell
6e926af41c Making executeMetaTransactionV2 nonpayable and addressing a few other minor issues 2023-03-21 14:42:45 -07:00
Patrick Dowell
172822044b Fixing multiHopSellOtcOrder when params.useSelfBalance is true 2023-02-24 10:45:49 -08:00
abls
a0485ca3e0 fix _computeHopTarget for otc subcalls 2023-02-24 05:14:03 -08:00
Patrick Dowell
f32e834e11 add multiHopBatchSellOtc to MultiplexFeature, fix _computeHopTarget for MultiplexSubcall.OTC [#667] 2023-02-23 23:27:35 -08:00
Patrick Dowell
b5c18c2a9e Removing ZERO_ADDRESS 2023-02-23 17:54:00 -08:00
Patrick Dowell
217348f31b cleaning up and adding batchExecuteMetaTransaction tests 2023-02-23 17:47:56 -08:00
Patrick Dowell
65a2024285 minor test fix 2023-02-23 17:12:57 -08:00
abls
b942551e33 prettier 2023-02-23 16:50:30 -08:00
abls
4c837110f2 add some tests for multiplex metatransactions 2023-02-23 16:39:07 -08:00
Patrick Dowell
88c96659a1 Fixing multiplex test failure 2023-02-23 13:26:20 -08:00
Patrick Dowell
152accf9c1 Complex rebase of test code based on changes in #655 2023-02-23 02:38:37 -08:00
Patrick Dowell
0f5d832daf Addressing suggestions from PR reviewers 2023-02-23 02:07:25 -08:00
Patrick Dowell
13dd95688d Fixing issues with EIP 712 signature, adding test case against MetaMask, and fixing lint issues 2023-02-23 02:07:25 -08:00
Patrick Dowell
15f79feb81 More linting 2023-02-23 02:07:25 -08:00
Patrick Dowell
3b55a88fc5 Ran prettier to clean up 2023-02-23 02:07:25 -08:00
Patrick Dowell
cdb94d1780 add multiplexBatchSellTokenForToken, multiplexMultiHopSellTokenForToken, multiplex TokenForEth functions to metatransactions, add msgSender field to multiplex params 2023-02-23 02:07:25 -08:00
Patrick Dowell
865c1f05db MetaTransactionV2 creation and forge tests 2023-02-23 02:07:25 -08:00
Patrick Dowell
2bbf3956f3 MetaTransactionData changes 2023-02-23 02:07:25 -08:00
Patrick Dowell
5cf4cbe4b5 MetaTransactionV2 creation and forge tests 2023-02-23 02:07:25 -08:00
Patrick Dowell
f402c96053 MetaTransactionData changes 2023-02-23 02:06:19 -08:00
151 changed files with 2578 additions and 10597 deletions

View File

@ -31,11 +31,6 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Add foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Build solution
run: yarn build
@ -83,30 +78,33 @@ jobs:
-p @0x/order-utils \
-m --serial -c test:ci
# NOTE: disabled as ZRXToken.sol did not compile with the latest forge.
# TODO: re-enable once the issue is resolved.
- 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 --skip ZRXToken
forge build --sizes
# - name: Run Forge tests for erc20
# working-directory: contracts/erc20
# run: |
# forge test -vvv --gas-report
- 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: 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: 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
@ -137,27 +135,3 @@ jobs:
path: ./contracts/zero-ex/lcov.info
min_coverage: 6.98
exclude: '**/tests'
- name: Run Forge build on governance contracts
working-directory: ./contracts/governance
run: |
forge --version
forge build --sizes
# TODO: re-enable once the issue is resolved.
# - name: Run Forge tests on governance contracts
# working-directory: ./contracts/governance
# run: |
# forge test -vvv --gas-report
# - name: Run Forge coverage on governance contracts
# working-directory: ./contracts/governance
# run: |
# forge coverage --report lcov
# - name: Upload the coverage report to Coveralls
# uses: coverallsapp/github-action@master
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# base-path: ./contracts/governance/
# path-to-lcov: ./contracts/governance/lcov.info

View File

@ -1,21 +1,19 @@
name: publish
on:
workflow_dispatch:
inputs:
ci_status:
description: 'required CI status'
default: 'success'
required: true
prerelease:
description: 'prerelease name'
required: false
workflow_dispatch:
inputs:
ci_status:
description: 'required CI status'
default: 'success'
required: true
prerelease:
description: 'prerelease name'
required: false
jobs:
publish:
runs-on: ubuntu-latest
env:
PublishBranch: publish/${{github.ref_name }}-${{ github.run_id }}-${{ github.run_number }}
steps:
- name: 'check successful status'
run: |
@ -24,26 +22,18 @@ jobs:
| jq .state)
[[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \
(echo "::error ::${{ github.ref }} does not have a successful CI status" && false)
- name: Add foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- uses: actions/checkout@v2
with:
ref: ${{ github.ref }}
fetch-depth: 0
ref: ${{ github.ref }}
fetch-depth: 0
- uses: actions/setup-node@v1
with:
node-version: 16
node-version: 16
- uses: actions/setup-python@v2
- name: 'configure git'
run: |
git config --global user.email "github-actions@github.com"
git config --global user.name "Github Actions"
- name: 'Checkout new branch'
run: |
git checkout -b $PublishBranch
git push -u origin $PublishBranch
- name: 'install dependencies'
run: |
yarn -D
@ -55,23 +45,9 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
PUBLISH_PRERELEASE: ${{ github.event.inputs.prerelease }}
- name: 'Create PR to merge into ref branch'
- name: 'merge into main branch'
if: github.event.inputs.prerelease == '' # unless it's a prerelease
run: |
gh pr create \
-B ${{ github.ref_name }} \
-H $PublishBranch \
--title "Publish: CHANGELOG and Package Version Updates into ${{ github.ref_name }}" \
--body "Syncing CHANGELOG and package version updates from publish action ${{github.run_id}}-${{github.run_number}} into ${{ github.ref_name}} branch" \
--reviewer ${{ github.actor }}
env:
GITHUB_TOKEN: ${{ github.token }}
- name: 'Create PR to merge ref branch into main'
run: |
gh pr create \
-B main \
-H ${{ github.ref_name }} \
--title "Publish: Sync ${{ github.ref_name }} into main " \
--body "Syncing ${{ github.ref_name }} back into main after publish action. NOTE: this PR should be merged after CHANGELOG and package version updates have been merged into ${{ github.ref_name }}" \
--reviewer ${{ github.actor }}
env:
GITHUB_TOKEN: ${{ github.token }}
git checkout main && \
git merge ${{ github.ref }} && \
git push

22
.gitignore vendored
View File

@ -63,16 +63,7 @@ typings/
.env
# built library using in commonjs module syntax
contracts/erc20/lib/
contracts/test-utils/lib/
contracts/treasury/lib/
contracts/utils/lib/
contracts/zero-ex/lib/
packages/contract-addresses/lib/
packages/contract-artifacts/lib/
packages/contract-wrappers/lib/
packages/protocol-utils/lib/
lib/
# UMD bundles that export the global variable
_bundles
@ -84,9 +75,6 @@ TODO.md
# IDE file
.vscode
.idea
*~
.\#*
\#*\#
# generated contract artifacts/
generated-artifacts/
@ -102,7 +90,6 @@ foundry-artifacts/
# foundry cache
cache/
foundry-cache/
#foundry output artifacts
out/
@ -110,17 +97,10 @@ out/
# typechain wrappers
contracts/zero-ex/typechain-wrappers/
# foundry packages
contracts/governance/cache
contracts/governance/out
# Doc README copy
packages/*/docs/README.md
.DS_Store
*~
\#*\#
.\#*
# the snapshot that gets built for migrations sure does have a ton of files
packages/migrations/0x_ganache_snapshot*

11
.gitmodules vendored
View File

@ -3,15 +3,4 @@
url = https://github.com/foundry-rs/forge-std
[submodule "contracts/erc20/lib/forge-std"]
path = contracts/erc20/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "contracts/governance/lib/forge-std"]
path = contracts/governance/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "contracts/governance/lib/openzeppelin-contracts"]
path = contracts/governance/lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
[submodule "contracts/governance/lib/openzeppelin-contracts-upgradeable"]
path = contracts/governance/lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/openzeppelin-contracts-upgradeable"]
branch = v4.8.2

View File

@ -1,138 +1,4 @@
[
{
"timestamp": 1700094997,
"version": "4.0.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1693346928,
"version": "4.0.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1692368658,
"version": "4.0.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1691617396,
"version": "4.0.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689974915,
"version": "4.0.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689791426,
"version": "4.0.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1683749017,
"version": "4.0.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1682976338,
"version": "4.0.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681969282,
"version": "4.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.0.5",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1681756154
},
{
"timestamp": 1681697326,
"version": "4.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681157139,
"version": "4.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1678410794,
"version": "4.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1677693479,
"version": "4.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.0.0",
"changes": [
{
"note": "Migrated package to foundry"
}
]
},
{
"timestamp": 1675210931,
"version": "3.3.57",

View File

@ -5,63 +5,7 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.0.14 - _November 16, 2023_
* Dependencies updated
## v4.0.13 - _August 29, 2023_
* Dependencies updated
## v4.0.12 - _August 18, 2023_
* Dependencies updated
## v4.0.11 - _August 9, 2023_
* Dependencies updated
## v4.0.10 - _July 21, 2023_
* Dependencies updated
## v4.0.9 - _July 19, 2023_
* Dependencies updated
## v4.0.8 - _May 10, 2023_
* Dependencies updated
## v4.0.7 - _May 1, 2023_
* Dependencies updated
## v4.0.6 - _April 20, 2023_
* Dependencies updated
## v4.0.5 - _April 17, 2023_
* Dependencies updated
## v4.0.4 - _April 17, 2023_
* Dependencies updated
## v4.0.3 - _April 10, 2023_
* Dependencies updated
## v4.0.2 - _March 10, 2023_
* Dependencies updated
## v4.0.1 - _March 1, 2023_
* Dependencies updated
## v4.0.0 - _Invalid date_
## v4.0.0 - _February 16, 2023_
* Migrated package to foundry

@ -1 +1 @@
Subproject commit fc560fa34fa12a335a50c35d92e55a6628ca467c
Subproject commit a2edd39db95df7e9dd3f9ef9edc8c55fefddb6df

View File

@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "4.0.14",
"version": "4.0.0",
"engines": {
"node": ">=6.12"
},
@ -24,10 +24,11 @@
},
"homepage": "https://github.com/0xProject/protocol",
"devDependencies": {
"@0x/contracts-utils": "^4.8.52",
"@0x/contracts-utils": "^4.8.38",
"@0x/ts-doc-gen": "^0.0.28",
"typedoc": "~0.16.11"
},
"dependencies": {},
"publishConfig": {
"access": "public"
},

View File

@ -39,6 +39,7 @@ contract WETH9V06Test is Test {
function testShouldConvertDepositedETHToWrappedETH() public {
vm.prank(user);
etherToken.deposit{value: 1e20}();
vm.stopPrank();
assertEq(etherToken.balanceOf(user), 1e20);
assertEq(address(etherToken).balance, 1e20);
@ -57,6 +58,7 @@ contract WETH9V06Test is Test {
etherToken.deposit{value: 1e20}();
vm.prank(user);
etherToken.withdraw(100);
vm.stopPrank();
assertEq(etherToken.balanceOf(user), 1e20 - 100);
assertEq(address(etherToken).balance, 1e20 - 100);
@ -66,6 +68,7 @@ contract WETH9V06Test is Test {
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);

View File

@ -34,6 +34,7 @@ contract ZRXTokenTest is Test {
assembly {
_address := create(0, add(_bytecode, 0x20), mload(_bytecode))
}
vm.stopPrank();
zrxToken = IERC20Token(address(_address));
}
@ -72,6 +73,7 @@ contract ZRXTokenTest is Test {
function testShouldReturnFalseIfSenderHasInsufficientBalance() public {
vm.prank(owner);
zrxToken.approve(user, totalSupply + 1);
vm.stopPrank();
bool success = zrxToken.transferFrom(owner, user, totalSupply + 1);
assertEq(success, false);
@ -80,6 +82,7 @@ contract ZRXTokenTest is Test {
function testShouldReturnFalseIfRecipientHasInsufficientAllowance() public {
vm.prank(owner);
zrxToken.approve(user, totalSupply - 1);
vm.stopPrank();
bool success = zrxToken.transferFrom(owner, user, totalSupply);
assertEq(success, false);
@ -94,6 +97,7 @@ contract ZRXTokenTest is Test {
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);
@ -102,6 +106,7 @@ contract ZRXTokenTest is Test {
function testShouldTransferCorrectlyWhenSufficientAllowance() public {
vm.prank(owner);
zrxToken.approve(user, 1000 * 1e18);
vm.stopPrank();
vm.prank(user);
zrxToken.transferFrom(owner, user, 100 * 1e18);

View File

@ -1,47 +0,0 @@
[
{
"timestamp": 1682976338,
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681756154,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681694690,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681687842,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681157139,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@ -1,26 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.5 - _May 1, 2023_
* Dependencies updated
## v1.0.4 - _April 17, 2023_
* Dependencies updated
## v1.0.3 - _April 17, 2023_
* Dependencies updated
## v1.0.2 - _April 16, 2023_
* Dependencies updated
## v1.0.1 - _April 10, 2023_
* Dependencies updated

View File

@ -1,74 +0,0 @@
## Governance
This package contains contracts for the ZeroEx governance of 0x Protocol and Treasury.
## Production deployment
`ZRXWrappedToken` 0xfcfaf7834f134f5146dbb3274bab9bed4bafa917
`ZeroExVotesProxy` 0x9c766e51b46cbc1fa4f8b6718ed4a60ac9d591fb
`ZeroExVotes` 0x8d208c5514b98c5b9ceed650b02df2aeb1c73e6f
Protocol `ZeroExTimelock` 0xb6a1f58c5df9f13312639cddda0d128bf28cdd87
`ZeroExProtocolGovernor` 0xc256035fe8533f9ce362012a6ae0aefed4df30f4
Treasury `ZeroExTimelock` 0x0dcfb77a581bc8fe432e904643a5480cc183f38d
`ZeroExTreasuryGovernor` 0x4822cfc1e7699bdb9551bdfd3a838ee414bc2008
Security council 0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F
## Design
This implementation fully decentralises governance of 0x Protocol and Treasury. This is enabled via a wrapped ZRX token and a Compound-like governors design. There are two separate governors for Protocol - `ZeroExProtocolGovernor` and Treasury - `ZeroExTreasuryGovernor` respectively working with two separate Timelock instances of the same contract implementation - `ZeroExTimelock`.
### Upgradability
`ZRXWrappedToken` , `ZeroExProtocolGovernor` and `ZeroExTreasuryGovernor` governors are non-upgradable by design. However the voting implementation the governors use - `ZeroExVotes` is upgradable and using the OZ `ERC1967Proxy`.
### Wrapped ZRX
wZRX will be issued 1-to-1 for ZRX. No locking/vesting mechanisms will exist between wZRX and ZRX and the two will be freely interchangeable. The ZRX token is non-upgradable and same will be valid for its wrapped equivalent.
The token supports delegation which allows a user to delegate their entire voting power to another account (which doesn't necessarily need to be a token holder). This is modelled on the standard OpenZeppelin `ERC20Votes` implementation. We have added logic for block number stamping delegators' balance changes stored in the `DelegateInfo.balanceLastUpdated` property. This block number information is sent in calls to `ZeroExVotes.moveVotingPower` in order to provide support for future upgrades to the vote power calculation.
Note that for consistency `block.number` is used for the governor settings, voting checkpoints and this delegators' balance last updated property while timelock logic for the governor uses block.timestamp.
### Governors' settings
Changing governors' settings for `votingDelay`, `votingPeriod` and `proposalThreshold` can be done via the normal proposal mechanism. Governors are deployed with the following initial settings:
| | voting delay | voting period | proposal threshold |
|-------------------|--------------|---------------|--------------------|
| Protocol governor | 2 days | 7 days | 1000000e18 |
| Treasury governor | 2 days | 7 days | 250000e18 |
This is using standard openzeppelin `GovernorSettings` implementation.
### Quorum
Quorum for Protocol is fixed at 10m (10000000e18) while for Treasury this is calculated as 10% of voting power of the total supply (see voting strategies below for quadratic voting power implementation specifics). The quorum calculations for Treasury are using OpenZeppelin's `GovernorVotesQuorumFraction`.
Note that in-place updates to the quorum are not supported and will need to go through a governance upgrade. Reasoning behind this can be found in this discussion https://forum.openzeppelin.com/t/quorum-default-behaviour-on-governors/34560.
### Voting strategies
The voting strategy will be linear 1-token-1-vote for Protocol and quadratic with threshold of 1000000e18 for Treasury (i.e. voting weight is linear up to 1m tokens and balance above that threshold is quadratic).
Worth noting is the `Checkpoint` struct design. For packing every `Checkpoint` into a single storage slot we are using the minimum uint type size for `votes` and `quadraticVotes` members, e.g.
```
struct Checkpoint {
uint32 fromBlock;
uint96 votes;
uint96 quadraticVotes;
}
```
since the maximum token supply is 1bn we can have maximum value for:
`votes` : 1bn *10^18 => can be stored in 90 bits
`quadraticVotes` : due to the likelihood of threshold changing and potentially bringing it closer to a linear vote, we are preemptively keeping this to the same size as linear votes slot.
### Time locks
Governance proposals are subject to a 3 days delay for Protocol and 2 days for Treasury. This delay allows Security Council time to review passed proposals and take action where needed.
### Security Council
The concept of a Security council is introduced which allows a multisig of security council members to cancel a proposal on the treasury or protocol governors and also rollback the protocol to an earlier version.
When no security council is assigned the following apply:
- ongoing proposals can still be voted on
- new proposals cannot be created - except assignSecurityCouncil
- expired proposals that are successful cannot be queued - excepted assignSecurityCouncil
There is a provision for the governors to have different security council set although initially these are the same.

View File

@ -1,505 +0,0 @@
{
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"inputs": [],
"payable": false,
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
],
"bytecode": {
"object": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b61078d8061004a6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058202dbef854545f38e5b78ec251d65db5fa0f12b6f2f0a0039063735c2dc416d6310029",
"sourceMap": "4935:353:0:-;;;5056:8;5027:37;;5208:78;;;;;;;5268:11;;-1:-1:-1;;;;;5254:10:0;5245:20;:8;:20;;;;;;;;;;:34;5208:78;4935:353;;;;;;;",
"linkReferences": {}
},
"deployedBytecode": {
"object": "0x606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058202dbef854545f38e5b78ec251d65db5fa0f12b6f2f0a0039063735c2dc416d6310029",
"sourceMap": "4935:353:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5109:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18:2:-1;;13:3;7:5;32;59:3;53:5;48:3;41:6;93:2;88:3;85:2;78:6;73:3;67:5;152:3;;;;;117:2;108:3;;;;130;172:5;167:4;181:3;3:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3523:190:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5027:37;;;;;;;;;;;;;;;;;;;;;;;;;;4369:562;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4986:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3415:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5164:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18:2:-1;;13:3;7:5;32;59:3;53:5;48:3;41:6;93:2;88:3;85:2;78:6;73:3;67:5;152:3;;;;;117:2;108:3;;;;130;172:5;167:4;181:3;3:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2490:433:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3719:129;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5109:49;;;;;;;;;;;;;;;;;;;:::o;3523:190::-;3599:19;3607:10;3599:19;;3583:4;3599:19;;;:7;:19;;;;;;;;:29;;;;;;;;;;;;:38;;;3647;;;;;;;3583:4;;3599:29;:19;3647:38;;;;;;;;;;;-1:-1:-1;3702:4:0;3523:190;;;;;:::o;5027:37::-;;;;:::o;4369:562::-;4487:14;;;;4451:4;4487:14;;;:7;:14;;;;;;;;4502:10;4487:26;;;;;;;;;;;;4527:15;;;;;;;;;;:25;;;;;;:48;;;4569:6;4556:9;:19;;4527:48;:91;;;;-1:-1:-1;4605:13:0;;;:8;:13;;;;;;;;;;;4579:22;;;:39;;4527:91;4523:402;;;4634:13;;;;:8;:13;;;;;;;;;;;:23;;;;;;4671:15;;;;;;:25;;;;;;;4069:12;4714:20;;4710:95;;;4754:14;;;;;;;;:7;:14;;;;;;;;4769:10;4754:26;;;;;;;;;:36;;;;;;;4710:95;4834:3;4818:28;;4827:5;4818:28;;;4839:6;4818:28;;;;;;;;;;;;;;;;;;4867:4;4860:11;;;;4523:402;4909:5;4902:12;;4523:402;4369:562;;;;;;;:::o;4986:35::-;5019:2;4986:35;:::o;3415:102::-;3494:16;;;3468:7;3494:16;;;;;;;;;;;3415:102;;;;:::o;5164:37::-;;;;;;;;;;;;;;;;;;;:::o;2490:433::-;2635:20;2644:10;2635:20;2546:4;2635:20;;;;;;;;;;;:30;;;;;;:73;;-1:-1:-1;2695:13:0;;;:8;:13;;;;;;;;;;;2669:22;;;:39;;2635:73;2631:286;;;2724:20;2733:10;2724:20;;:8;:20;;;;;;;;;;;:30;;;;;;;2768:13;;;;;;;;;;:23;;;;;;2805:33;;;;;;;2768:13;;2805:33;;;;;;;;;;;-1:-1:-1;2859:4:0;2852:11;;2631:286;-1:-1:-1;2901:5:0;2894:12;;2631:286;2490:433;;;;;:::o;3719:129::-;3816:15;;;;3790:7;3816:15;;;:7;:15;;;;;;;;:25;;;;;;;;;;3719:129;;;;;:::o",
"linkReferences": {}
},
"methodIdentifiers": {
"allowance(address,address)": "dd62ed3e",
"approve(address,uint256)": "095ea7b3",
"balanceOf(address)": "70a08231",
"decimals()": "313ce567",
"name()": "06fdde03",
"symbol()": "95d89b41",
"totalSupply()": "18160ddd",
"transfer(address,uint256)": "a9059cbb",
"transferFrom(address,address,uint256)": "23b872dd"
},
"rawMetadata": "{\"compiler\":{\"version\":\"0.4.11+commit.68ef5810\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"transferFrom(address,address,uint256)\":{\"details\":\"ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.\",\"params\":{\"_from\":\"Address to transfer from.\",\"_to\":\"Address to transfer to.\",\"_value\":\"Amount to transfer.\"},\"return\":\"Success of transfer.\"}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/erc20/src/ZRXToken.sol\":\"ZRXToken\"},\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@0x/contracts-erc20/=contracts/erc20/\",\":@0x/contracts-utils/=contracts/utils/\",\":ds-test/=contracts/erc20/lib/forge-std/lib/ds-test/src/\",\":forge-std/=contracts/erc20/lib/forge-std/src/\"]},\"sources\":{\"contracts/erc20/src/ZRXToken.sol\":{\"keccak256\":\"0x8582c06b20f8b7d3d603b485b5d26f840e01d1986381b334a856833edcff0d47\",\"urls\":[\"bzzr://ef728dddbaa1e26baa6cc9fe0f83de5055bc0b17dfe488018f4ee59d68ccb5dd\"]}},\"version\":1}",
"metadata": {
"compiler": {
"version": "0.4.11+commit.68ef5810"
},
"language": "Solidity",
"output": {
"abi": [
{
"inputs": [],
"type": "function",
"name": "name",
"outputs": [
{
"internalType": null,
"name": "",
"type": "string"
}
]
},
{
"inputs": [
{
"internalType": null,
"name": "_spender",
"type": "address"
},
{
"internalType": null,
"name": "_value",
"type": "uint256"
}
],
"type": "function",
"name": "approve",
"outputs": [
{
"internalType": null,
"name": "",
"type": "bool"
}
]
},
{
"inputs": [],
"type": "function",
"name": "totalSupply",
"outputs": [
{
"internalType": null,
"name": "",
"type": "uint256"
}
]
},
{
"inputs": [
{
"internalType": null,
"name": "_from",
"type": "address"
},
{
"internalType": null,
"name": "_to",
"type": "address"
},
{
"internalType": null,
"name": "_value",
"type": "uint256"
}
],
"type": "function",
"name": "transferFrom",
"outputs": [
{
"internalType": null,
"name": "",
"type": "bool"
}
]
},
{
"inputs": [],
"type": "function",
"name": "decimals",
"outputs": [
{
"internalType": null,
"name": "",
"type": "uint8"
}
]
},
{
"inputs": [
{
"internalType": null,
"name": "_owner",
"type": "address"
}
],
"type": "function",
"name": "balanceOf",
"outputs": [
{
"internalType": null,
"name": "",
"type": "uint256"
}
]
},
{
"inputs": [],
"type": "function",
"name": "symbol",
"outputs": [
{
"internalType": null,
"name": "",
"type": "string"
}
]
},
{
"inputs": [
{
"internalType": null,
"name": "_to",
"type": "address"
},
{
"internalType": null,
"name": "_value",
"type": "uint256"
}
],
"type": "function",
"name": "transfer",
"outputs": [
{
"internalType": null,
"name": "",
"type": "bool"
}
]
},
{
"inputs": [
{
"internalType": null,
"name": "_owner",
"type": "address"
},
{
"internalType": null,
"name": "_spender",
"type": "address"
}
],
"type": "function",
"name": "allowance",
"outputs": [
{
"internalType": null,
"name": "",
"type": "uint256"
}
]
},
{
"inputs": [],
"type": "constructor"
},
{
"inputs": [
{
"internalType": null,
"name": "_from",
"type": "address",
"indexed": true
},
{
"internalType": null,
"name": "_to",
"type": "address",
"indexed": true
},
{
"internalType": null,
"name": "_value",
"type": "uint256",
"indexed": false
}
],
"type": "event",
"name": "Transfer",
"anonymous": false
},
{
"inputs": [
{
"internalType": null,
"name": "_owner",
"type": "address",
"indexed": true
},
{
"internalType": null,
"name": "_spender",
"type": "address",
"indexed": true
},
{
"internalType": null,
"name": "_value",
"type": "uint256",
"indexed": false
}
],
"type": "event",
"name": "Approval",
"anonymous": false
}
],
"devdoc": {
"methods": {
"transferFrom(address,address,uint256)": {
"details": "ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.",
"params": {
"_from": "Address to transfer from.",
"_to": "Address to transfer to.",
"_value": "Amount to transfer."
},
"return": "Success of transfer."
}
}
},
"userdoc": {
"methods": {}
}
},
"settings": {
"remappings": [
":@0x/contracts-erc20/=contracts/erc20/",
":@0x/contracts-utils/=contracts/utils/",
":ds-test/=contracts/erc20/lib/forge-std/lib/ds-test/src/",
":forge-std/=contracts/erc20/lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"compilationTarget": {
"contracts/erc20/src/ZRXToken.sol": "ZRXToken"
},
"libraries": {}
},
"sources": {
"contracts/erc20/src/ZRXToken.sol": {
"keccak256": "0x8582c06b20f8b7d3d603b485b5d26f840e01d1986381b334a856833edcff0d47",
"urls": ["bzzr://ef728dddbaa1e26baa6cc9fe0f83de5055bc0b17dfe488018f4ee59d68ccb5dd"],
"license": null
}
},
"version": 1
},
"id": 0
}

View File

@ -1,37 +0,0 @@
[profile.default]
src = 'src'
out = 'out'
libs = ['lib', "../utils/contracts/src/"]
match_path = "test/unit/*.sol"
fs_permissions = [{ access = "read", path = "./" }]
remappings = [
'@openzeppelin/=./lib/openzeppelin-contracts/contracts/',
'@openzeppelin-contracts-upgradeable/=./lib/openzeppelin-contracts-upgradeable/contracts/',
'@0x/contracts-utils/=../utils/',
]
solc = '0.8.19'
optimizer_runs = 20_000
via_ir = true
[profile.integration]
match_path = "test/integration/*.sol"
gas_price = 31_000_000_000
[rpc_endpoints]
goerli = "${GOERLI_RPC_URL}"
mainnet = "${MAINNET_RPC_URL}"
[etherscan]
goerli = { key = "${ETHERSCAN_API_KEY}" }
[profile.smt.model_checker]
engine = 'chc'
timeout = 10_000
targets = [
'assert',
'constantCondition',
'divByZero',
'outOfBounds',
'underflow'
]
contracts = { 'src/ZeroExProtocolGovernor.sol' = [ 'ZeroExProtocolGovernor' ] }

@ -1 +0,0 @@
Subproject commit eb980e1d4f0e8173ec27da77297ae411840c8ccb

@ -1 +0,0 @@
Subproject commit d00acef4059807535af0bd0dd0ddf619747a044b

@ -1 +0,0 @@
Subproject commit f6c4c9c4ec601665ca74d2c9dddf547fc425658c

View File

@ -1,27 +0,0 @@
{
"name": "@0x/governance",
"version": "1.0.5",
"description": "Governance implementation for the 0x protocol and treasury",
"main": "index.js",
"directories": {
"lib": "lib",
"test": "test"
},
"scripts": {
"test": "forge test",
"build": "forge build",
"build:smt": "FOUNDRY_PROFILE=smt forge build",
"test:integration": "source .env && FOUNDRY_PROFILE=integration forge test --fork-url $MAINNET_RPC_URL --fork-block-number 16884148 -vvv",
"goerli:deploy:zrxtoken": "source .env && forge script script/DeployToken.s.sol:Deploy --rpc-url $GOERLI_RPC_URL --broadcast --slow -vvvv",
"goerli:deploy:governance": "source .env && forge script script/DeployGovernance.s.sol:Deploy --rpc-url $GOERLI_RPC_URL --broadcast --slow -vvvv",
"mainnet:deploy:governance": "source .env && forge script script/DeployGovernance.s.sol:Deploy --rpc-url $MAINNET_RPC_URL --broadcast --slow -vvvv"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/protocol.git"
},
"publishConfig": {
"access": "public"
},
"license": "Apache-2.0"
}

View File

@ -1,80 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import "forge-std/Script.sol";
import "forge-std/console.sol";
import "forge-std/console2.sol";
import "@openzeppelin/token/ERC20/IERC20.sol";
import "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
import "../src/ZRXWrappedToken.sol";
import "../src/ZeroExVotes.sol";
import "../src/ZeroExTimelock.sol";
import "../src/ZeroExProtocolGovernor.sol";
import "../src/ZeroExTreasuryGovernor.sol";
contract Deploy is Script {
address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
address internal constant EXCHANGE = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
address payable internal constant SECURITY_COUNCIL = payable(0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F);
uint256 internal constant QUADRATIC_THRESHOLD = 1000000e18;
function setUp() public {}
function run() external {
address deployer = vm.envAddress("DEPLOYER");
vm.startBroadcast(deployer);
console2.log("Zrx Token", ZRX_TOKEN);
address wTokenPrediction = predict(deployer, vm.getNonce(deployer) + 2);
ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, QUADRATIC_THRESHOLD);
ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
ZRXWrappedToken wToken = new ZRXWrappedToken(IERC20(ZRX_TOKEN), ZeroExVotes(address(votesProxy)));
assert(address(wToken) == wTokenPrediction);
console2.log("Wrapped Token", address(wToken));
ZeroExVotes votes = ZeroExVotes(address(votesProxy));
console2.log("Votes", address(votes));
address[] memory proposers = new address[](0);
address[] memory executors = new address[](0);
ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, deployer);
console2.log("Protocol timelock", address(protocolTimelock));
ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
IVotes(address(votes)),
protocolTimelock,
SECURITY_COUNCIL
);
protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
protocolTimelock.renounceRole(protocolTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
console2.log("Protocol governor", address(protocolGovernor));
ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, deployer);
console2.log("Treasury timelock", address(treasuryTimelock));
ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
IVotes(address(votes)),
treasuryTimelock,
SECURITY_COUNCIL
);
treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
treasuryTimelock.renounceRole(treasuryTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
console2.log("Treasury governor", address(treasuryGovernor));
console2.log(unicode"0x governance deployed successfully 🎉");
vm.stopBroadcast();
}
function predict(address deployer, uint256 nonce) internal pure returns (address) {
require(nonce > 0 && nonce < 128, "Invalid nonce");
return address(uint160(uint256(keccak256(abi.encodePacked(bytes2(0xd694), deployer, bytes1(uint8(nonce)))))));
}
}

View File

@ -1,22 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import "forge-std/Script.sol";
import "forge-std/console2.sol";
contract Deploy is Script {
function setUp() public {}
function run() external {
vm.startBroadcast(vm.envAddress("DEPLOYER"));
bytes memory _bytecode = vm.getCode("./ZRXToken.json");
address zrxToken;
assembly {
zrxToken := create(0, add(_bytecode, 0x20), mload(_bytecode))
}
console2.log("Zrx Token", zrxToken);
console2.log(unicode"Zrx Token deployed successfully 🎉");
vm.stopBroadcast();
}
}

View File

@ -1,169 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library CallWithGas {
/**
* @notice `staticcall` another contract forwarding a precomputed amount of
* gas.
* @dev contains protections against EIP-150-induced insufficient gas
* griefing
* @dev reverts iff the target is not a contract or we encounter an
* out-of-gas
* @return success true iff the call succeded and returned no more than
* `maxReturnBytes` of return data
* @return returnData the return data or revert reason of the call
* @param target the contract (reverts if non-contract) on which to make the
* `staticcall`
* @param data the calldata to pass
* @param callGas the gas to pass for the call. If the call requires more than
* the specified amount of gas and the caller didn't provide at
* least `callGas`, triggers an out-of-gas in the caller.
* @param maxReturnBytes Only this many bytes of return data are read back
* from the call. This prevents griefing the caller. If
* more bytes are returned or the revert reason is
* longer, success will be false and returnData will be
* `abi.encodeWithSignature("Error(string)", "CallWithGas: returnData too long")`
*/
function functionStaticCallWithGas(
address target,
bytes memory data,
uint256 callGas,
uint256 maxReturnBytes
) internal view returns (bool success, bytes memory returnData) {
assembly ("memory-safe") {
returnData := mload(0x40)
success := staticcall(callGas, target, add(data, 0x20), mload(data), add(returnData, 0x20), maxReturnBytes)
// As of the time this contract was written, `verbatim` doesn't work in
// inline assembly. Assignment of a value to a variable costs gas
// (although how much is unpredictable because it depends on the Yul/IR
// optimizer), as does the `GAS` opcode itself. Also solc tends to reorder
// the call to `gas()` with preparing the arguments for `div`. Therefore,
// the `gas()` below returns less than the actual amount of gas available
// for computation at the end of the call. That makes this check slightly
// too conservative. However, we do not correct for this because the
// correction would become outdated (possibly too permissive) if the
// opcodes are repriced.
// https://eips.ethereum.org/EIPS/eip-150
// https://ronan.eth.link/blog/ethereum-gas-dangers/
if iszero(or(success, or(returndatasize(), lt(div(callGas, 63), gas())))) {
// The call failed due to not enough gas left. We deliberately consume
// all remaining gas with `invalid` (instead of `revert`) to make this
// failure distinguishable to our caller.
invalid()
}
switch gt(returndatasize(), maxReturnBytes)
case 0 {
switch returndatasize()
case 0 {
returnData := 0x60
success := and(success, iszero(iszero(extcodesize(target))))
}
default {
mstore(returnData, returndatasize())
mstore(0x40, add(returnData, add(0x20, returndatasize())))
}
}
default {
// returnData = abi.encodeWithSignature("Error(string)", "CallWithGas: returnData too long")
success := 0
mstore(returnData, 0) // clear potentially dirty bits
mstore(add(returnData, 0x04), 0x6408c379a0) // length and selector
mstore(add(returnData, 0x24), 0x20)
mstore(add(returnData, 0x44), 0x20)
mstore(add(returnData, 0x64), "CallWithGas: returnData too long")
mstore(0x40, add(returnData, 0x84))
}
}
}
/// See `functionCallWithGasAndValue`
function functionCallWithGas(
address target,
bytes memory data,
uint256 callGas,
uint256 maxReturnBytes
) internal returns (bool success, bytes memory returnData) {
return functionCallWithGasAndValue(payable(target), data, callGas, 0, maxReturnBytes);
}
/**
* @notice `call` another contract forwarding a precomputed amount of gas.
* @notice Unlike `functionStaticCallWithGas`, a failure is not signaled if
* there is too much return data. Instead, it is simply truncated.
* @dev contains protections against EIP-150-induced insufficient gas griefing
* @dev reverts iff caller doesn't have enough native asset balance, the
* target is not a contract, or due to out-of-gas
* @return success true iff the call succeded
* @return returnData the return data or revert reason of the call
* @param target the contract (reverts if non-contract) on which to make the
* `call`
* @param data the calldata to pass
* @param callGas the gas to pass for the call. If the call requires more than
* the specified amount of gas and the caller didn't provide at
* least `callGas`, triggers an out-of-gas in the caller.
* @param value the amount of the native asset in wei to pass to the callee
* with the call
* @param maxReturnBytes Only this many bytes of return data/revert reason are
* read back from the call. This prevents griefing the
* caller. If more bytes are returned or the revert
* reason is longer, returnData will be truncated
*/
function functionCallWithGasAndValue(
address payable target,
bytes memory data,
uint256 callGas,
uint256 value,
uint256 maxReturnBytes
) internal returns (bool success, bytes memory returnData) {
if (value > 0 && (address(this).balance < value || target.code.length == 0)) {
return (success, returnData);
}
assembly ("memory-safe") {
returnData := mload(0x40)
success := call(callGas, target, value, add(data, 0x20), mload(data), add(returnData, 0x20), maxReturnBytes)
// As of the time this contract was written, `verbatim` doesn't work in
// inline assembly. Assignment of a value to a variable costs gas
// (although how much is unpredictable because it depends on the Yul/IR
// optimizer), as does the `GAS` opcode itself. Also solc tends to reorder
// the call to `gas()` with preparing the arguments for `div`. Therefore,
// the `gas()` below returns less than the actual amount of gas available
// for computation at the end of the call. That makes this check slightly
// too conservative. However, we do not correct for this because the
// correction would become outdated (possibly too permissive) if the
// opcodes are repriced.
// https://eips.ethereum.org/EIPS/eip-150
// https://ronan.eth.link/blog/ethereum-gas-dangers/
if iszero(or(success, or(returndatasize(), lt(div(callGas, 63), gas())))) {
// The call failed due to not enough gas left. We deliberately consume
// all remaining gas with `invalid` (instead of `revert`) to make this
// failure distinguishable to our caller.
invalid()
}
switch gt(returndatasize(), maxReturnBytes)
case 0 {
switch returndatasize()
case 0 {
returnData := 0x60
if iszero(value) {
success := and(success, iszero(iszero(extcodesize(target))))
}
}
default {
mstore(returnData, returndatasize())
mstore(0x40, add(returnData, add(0x20, returndatasize())))
}
}
default {
mstore(returnData, maxReturnBytes)
mstore(0x40, add(returnData, add(0x20, maxReturnBytes)))
}
}
}
}

View File

@ -1,39 +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.19;
import "./SecurityCouncil.sol";
import "@openzeppelin/governance/IGovernor.sol";
import "@openzeppelin/governance/extensions/IGovernorTimelock.sol";
abstract contract IZeroExGovernor is SecurityCouncil, IGovernor, IGovernorTimelock {
function token() public virtual returns (address);
function proposalThreshold() public view virtual returns (uint256);
function setVotingDelay(uint256 newVotingDelay) public virtual;
function setVotingPeriod(uint256 newVotingPeriod) public virtual;
function setProposalThreshold(uint256 newProposalThreshold) public virtual;
function proposalVotes(
uint256 proposalId
) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes);
}

View File

@ -1,132 +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.19;
interface IZeroExVotes {
struct Checkpoint {
uint32 fromBlock;
uint96 votes;
uint96 quadraticVotes;
}
/**
* @dev Emitted when a token transfer or delegate change,
* results in changes to a delegate's quadratic number of votes.
*/
event DelegateQuadraticVotesChanged(
address indexed delegate,
uint256 previousQuadraticBalance,
uint256 newQuadraticBalance
);
/**
* @dev Emitted when a token transfer or delegate change, results in changes to a delegate's number of votes.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
/**
* @dev Emitted when the total supply of the token is changed due to minting and burning which results in
* the total supply checkpoint being writtenor updated.
*/
event TotalSupplyChanged(uint256 totalSupplyVotes, uint256 totalSupplyQuadraticVotes);
/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function checkpoints(address account, uint32 pos) external view returns (Checkpoint memory);
/**
* @dev Get number of checkpoints for `account`.
*/
function numCheckpoints(address account) external view returns (uint32);
/**
* @dev Gets the current votes balance for `account`
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Gets the current quadratic votes balance for `account`
*/
function getQuadraticVotes(address account) external view returns (uint256);
/**
* @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
/**
* @dev Retrieve the number of quadratic votes for `account` at the end of `blockNumber`.
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastQuadraticVotes(address account, uint256 blockNumber) external view returns (uint256);
/**
* @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
* It is but NOT the sum of all the delegated votes!
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
/**
* @dev Retrieve the sqrt of `totalSupply` at the end of `blockNumber`. Note, this value is the square root of the
* sum of all balances.
* It is but NOT the sum of all the sqrt of the delegated votes!
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastQuadraticTotalSupply(uint256 blockNumber) external view returns (uint256);
/**
* @dev Moves the voting power corresponding to `amount` number of tokens from `src` to `dst`.
* Note that if the delegator isn't delegating to anyone before the function call `src` = address(0)
* @param src the delegatee we are moving voting power away from
* @param dst the delegatee we are moving voting power to
* @param srcBalance balance of the delegator whose delegatee is `src`. This is value _after_ the transfer.
* @param dstBalance balance of the delegator whose delegatee is `dst`. This is value _after_ the transfer.
* @param srcBalanceLastUpdated block number when balance of `src` was last updated.
* @param dstBalanceLastUpdated block number when balance of `dst` was last updated.
* @param amount The amount of tokens transferred from the source delegate to destination delegate.
*/
function moveVotingPower(
address src,
address dst,
uint256 srcBalance,
uint256 dstBalance,
uint96 srcBalanceLastUpdated,
uint96 dstBalanceLastUpdated,
uint256 amount
) external returns (bool);
function writeCheckpointTotalSupplyMint(uint256 accountBalance, uint256 amount) external returns (bool);
function writeCheckpointTotalSupplyBurn(uint256 accountBalance, uint256 amount) external returns (bool);
}

View File

@ -1,85 +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.19;
abstract contract SecurityCouncil {
address public securityCouncil;
event SecurityCouncilAssigned(address securityCouncil);
event SecurityCouncilEjected();
modifier onlySecurityCouncil() {
_checkSenderIsSecurityCouncil();
_;
}
/**
* @dev Checks that either a security council is assigned or the payloads array is a council assignment call.
*/
modifier securityCouncilAssigned(bytes[] memory payloads) {
if (securityCouncil == address(0) && !_payloadIsAssignSecurityCouncil(payloads)) {
revert("SecurityCouncil: security council not assigned and this is not an assignment call");
}
_;
}
/**
* @dev Assigns new security council.
*/
function assignSecurityCouncil(address _securityCouncil) public virtual {
securityCouncil = _securityCouncil;
emit SecurityCouncilAssigned(securityCouncil);
}
/**
* @dev Ejects the current security council via setting the security council address to 0.
* Security council is ejected after they either cancel a proposal or execute a protocol rollback.
*/
function ejectSecurityCouncil() internal {
securityCouncil = address(0);
emit SecurityCouncilEjected();
}
/**
* @dev Cancel existing proposal with the submitted `targets`, `values`, `calldatas` and `descriptionHash`.
*/
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public virtual;
function _payloadIsAssignSecurityCouncil(bytes[] memory payloads) private pure returns (bool) {
require(payloads.length == 1, "SecurityCouncil: more than 1 transaction in proposal");
bytes memory payload = payloads[0];
// Check this is as assignSecurityCouncil(address) transaction
// function signature for assignSecurityCouncil(address)
// = bytes4(keccak256("assignSecurityCouncil(address)"))
// = 0x2761c3cd
if (bytes4(payload) == bytes4(0x2761c3cd)) return true;
else return false;
}
function _checkSenderIsSecurityCouncil() private view {
require(msg.sender == securityCouncil, "SecurityCouncil: only security council allowed");
}
}

View File

@ -1,164 +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.19;
import "@openzeppelin/token/ERC20/ERC20.sol";
import "@openzeppelin/token/ERC20/extensions/draft-ERC20Permit.sol";
import "@openzeppelin/token/ERC20/extensions/ERC20Wrapper.sol";
import "@openzeppelin/governance/utils/IVotes.sol";
import "@openzeppelin/utils/math/SafeCast.sol";
import "./IZeroExVotes.sol";
import "./CallWithGas.sol";
contract ZRXWrappedToken is ERC20, ERC20Permit, ERC20Wrapper {
using CallWithGas for address;
struct DelegateInfo {
address delegate;
uint96 balanceLastUpdated;
}
constructor(
IERC20 wrappedToken,
IZeroExVotes _zeroExVotes
) ERC20("Wrapped ZRX", "wZRX") ERC20Permit("Wrapped ZRX") ERC20Wrapper(wrappedToken) {
zeroExVotes = _zeroExVotes;
}
IZeroExVotes public immutable zeroExVotes;
mapping(address => DelegateInfo) private _delegates;
bytes32 private constant _DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
// The functions below are the required overrides from the base contracts
function decimals() public pure override(ERC20, ERC20Wrapper) returns (uint8) {
return 18;
}
function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20) {
super._afterTokenTransfer(from, to, amount);
DelegateInfo memory fromDelegate = delegateInfo(from);
DelegateInfo memory toDelegate = delegateInfo(to);
uint256 fromBalance = fromDelegate.delegate == address(0) ? 0 : balanceOf(from) + amount;
uint256 toBalance = toDelegate.delegate == address(0) ? 0 : balanceOf(to) - amount;
if (fromDelegate.delegate != address(0)) _delegates[from].balanceLastUpdated = SafeCast.toUint96(block.number);
if (toDelegate.delegate != address(0)) _delegates[to].balanceLastUpdated = SafeCast.toUint96(block.number);
zeroExVotes.moveVotingPower(
fromDelegate.delegate,
toDelegate.delegate,
fromBalance,
toBalance,
fromDelegate.balanceLastUpdated,
toDelegate.balanceLastUpdated,
amount
);
}
function _mint(address account, uint256 amount) internal override(ERC20) {
super._mint(account, amount);
zeroExVotes.writeCheckpointTotalSupplyMint(balanceOf(account) - amount, amount);
}
function _burn(address account, uint256 amount) internal override(ERC20) {
super._burn(account, amount);
address(zeroExVotes).functionCallWithGas(
abi.encodeCall(zeroExVotes.writeCheckpointTotalSupplyBurn, (balanceOf(account) + amount, amount)),
500_000,
32
);
}
/**
* @dev Get the address `account` is currently delegating to.
*/
function delegates(address account) public view returns (address) {
return _delegates[account].delegate;
}
/**
* @dev Get the last block number when `account`'s balance changed.
*/
function delegatorBalanceLastUpdated(address account) public view returns (uint96) {
return _delegates[account].balanceLastUpdated;
}
function delegateInfo(address account) public view returns (DelegateInfo memory) {
return _delegates[account];
}
/**
* @dev Delegate votes from the sender to `delegatee`.
*/
function delegate(address delegatee) public {
_delegate(_msgSender(), delegatee);
}
/**
* @dev Delegates votes from signer to `delegatee`
*/
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) public {
require(block.timestamp <= expiry, "ERC20Votes: signature expired");
address signer = ECDSA.recover(
_hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
v,
r,
s
);
require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
_delegate(signer, delegatee);
}
/**
* @dev Change delegation for `delegator` to `delegatee`.
*
* Emits events {DelegateChanged} and {IZeroExVotes-DelegateVotesChanged}.
*/
function _delegate(address delegator, address delegatee) internal virtual {
DelegateInfo memory delegateInfo = delegateInfo(delegator);
uint256 delegatorBalance = balanceOf(delegator);
_delegates[delegator] = DelegateInfo(delegatee, SafeCast.toUint96(block.timestamp));
emit DelegateChanged(delegator, delegateInfo.delegate, delegatee);
zeroExVotes.moveVotingPower(
delegateInfo.delegate,
delegatee,
delegatorBalance,
0,
delegateInfo.balanceLastUpdated,
0,
delegatorBalance
);
}
}

View File

@ -1,145 +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.19;
import "./SecurityCouncil.sol";
import "./ZeroExTimelock.sol";
import "@openzeppelin/governance/Governor.sol";
import "@openzeppelin/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";
contract ZeroExProtocolGovernor is
SecurityCouncil,
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorTimelockControl
{
constructor(
IVotes _votes,
ZeroExTimelock _timelock,
address _securityCouncil
)
Governor("ZeroExProtocolGovernor")
GovernorSettings(14400 /* 2 days */, 50400 /* 7 days */, 1000000e18)
GovernorVotes(_votes)
GovernorTimelockControl(TimelockController(payable(_timelock)))
{
securityCouncil = _securityCouncil;
}
function quorum(uint256 blockNumber) public pure override returns (uint256) {
return 10000000e18;
}
// The following functions are overrides required by Solidity.
function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {
return super.votingDelay();
}
function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {
return super.votingPeriod();
}
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
return super.state(proposalId);
}
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) public override(Governor, IGovernor) securityCouncilAssigned(calldatas) returns (uint256) {
return super.propose(targets, values, calldatas, description);
}
function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
return super.proposalThreshold();
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public override onlySecurityCouncil {
_cancel(targets, values, calldatas, descriptionHash);
}
// Like the GovernorTimelockControl.queue function but without the proposal checks,
// (as there's effectively no proposal).
// And also using a delay of 0 as opposed to the minimum delay of the timelock
function executeRollback(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public onlySecurityCouncil {
// Execute the batch of rollbacks via the timelock controller
ZeroExTimelock timelockController = ZeroExTimelock(payable(timelock()));
timelockController.executeRollbackBatch(targets, values, calldatas, 0, descriptionHash);
}
function assignSecurityCouncil(address _securityCouncil) public override onlyGovernance {
super.assignSecurityCouncil(_securityCouncil);
}
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public override securityCouncilAssigned(calldatas) returns (uint256) {
return super.queue(targets, values, calldatas, descriptionHash);
}
function _execute(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) {
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
return super._executor();
}
function supportsInterface(
bytes4 interfaceId
) public view override(Governor, GovernorTimelockControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
}

View File

@ -1,70 +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.19;
import "@openzeppelin/governance/TimelockController.sol";
contract ZeroExTimelock is TimelockController {
// minDelay is how long you have to wait before executing
// proposers is the list of addresses that can propose
// executors is the list of addresses that can execute
constructor(
uint256 minDelay,
address[] memory proposers,
address[] memory executors,
address admin
) TimelockController(minDelay, proposers, executors, admin) {}
/**
* @dev Execute a batch of rollback transactions. Similar to TimelockController.executeBatch function but without
* the timelock checks.
* Emits one {CallExecuted} event per transaction in the batch.
*
* Requirements:
*
* - the caller must have the 'executor' role.
*/
function executeRollbackBatch(
address[] calldata targets,
uint256[] calldata values,
bytes[] calldata payloads,
bytes32 predecessor,
bytes32 salt
) public payable onlyRoleOrOpenRole(EXECUTOR_ROLE) {
require(targets.length > 0, "ZeroExTimelock: empty targets");
require(targets.length == values.length, "ZeroExTimelock: length mismatch");
require(targets.length == payloads.length, "ZeroExTimelock: length mismatch");
bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);
for (uint256 i = 0; i < targets.length; ++i) {
address target = targets[i];
uint256 value = values[i];
bytes calldata payload = payloads[i];
// Check this is a rollback transaction
// function signature for rollback(bytes4,address)
// = bytes4(keccak256("rollback(bytes4,address)"))
// = 0x9db64a40
require(bytes4(payload) == bytes4(0x9db64a40), "ZeroExTimelock: not rollback");
_execute(target, value, payload);
emit CallExecuted(id, i, target, value, payload);
}
}
}

View File

@ -1,154 +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.19;
import "@openzeppelin/governance/Governor.sol";
import "@openzeppelin/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";
import "./IZeroExVotes.sol";
import "./SecurityCouncil.sol";
contract ZeroExTreasuryGovernor is
SecurityCouncil,
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction,
GovernorTimelockControl
{
constructor(
IVotes votes,
TimelockController _timelock,
address _securityCouncil
)
Governor("ZeroExTreasuryGovernor")
GovernorSettings(14400 /* 2 days */, 50400 /* 7 days */, 250000e18)
GovernorVotes(votes)
GovernorVotesQuorumFraction(10)
GovernorTimelockControl(_timelock)
{
securityCouncil = _securityCouncil;
}
/**
* @dev Returns the "quadratic" quorum for a block number, in terms of number of votes:
* `quadratic total supply * numerator / denominator`
*/
function quorum(
uint256 blockNumber
) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) {
IZeroExVotes votes = IZeroExVotes(address(token));
return (votes.getPastQuadraticTotalSupply(blockNumber) * quorumNumerator(blockNumber)) / quorumDenominator();
}
// The following functions are overrides required by Solidity.
function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {
return super.votingDelay();
}
function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {
return super.votingPeriod();
}
function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
return super.proposalThreshold();
}
/**
* Overwritten GovernorVotes implementation
* Read the quadratic voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}).
*/
function _getVotes(
address account,
uint256 blockNumber,
bytes memory /*params*/
) internal view virtual override(Governor, GovernorVotes) returns (uint256) {
return IZeroExVotes(address(token)).getPastQuadraticVotes(account, blockNumber);
}
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
return super.state(proposalId);
}
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) public override(Governor, IGovernor) securityCouncilAssigned(calldatas) returns (uint256) {
return super.propose(targets, values, calldatas, description);
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public override onlySecurityCouncil {
_cancel(targets, values, calldatas, descriptionHash);
}
function assignSecurityCouncil(address _securityCouncil) public override onlyGovernance {
super.assignSecurityCouncil(_securityCouncil);
}
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public override securityCouncilAssigned(calldatas) returns (uint256) {
return super.queue(targets, values, calldatas, descriptionHash);
}
function _execute(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) {
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
return super._executor();
}
function supportsInterface(
bytes4 interfaceId
) public view override(Governor, GovernorTimelockControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
}

View File

@ -1,336 +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.19;
import "@openzeppelin/utils/math/SafeCast.sol";
import "@openzeppelin/utils/math/Math.sol";
import "@openzeppelin/token/ERC20/ERC20.sol";
import "@openzeppelin/governance/utils/IVotes.sol";
import "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin-contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol";
import "./IZeroExVotes.sol";
contract ZeroExVotes is IZeroExVotes, Initializable, OwnableUpgradeable, UUPSUpgradeable {
address public immutable token;
uint256 public immutable quadraticThreshold;
mapping(address => Checkpoint[]) internal _checkpoints;
Checkpoint[] private _totalSupplyCheckpoints;
constructor(address _token, uint256 _quadraticThreshold) {
require(_token != address(0), "ZeroExVotes: token cannot be 0");
token = _token;
quadraticThreshold = _quadraticThreshold;
_disableInitializers();
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
modifier onlyToken() {
_checkSenderIsToken();
_;
}
function initialize() public virtual onlyProxy initializer {
__Ownable_init();
__UUPSUpgradeable_init();
}
/**
* @inheritdoc IZeroExVotes
*/
function checkpoints(address account, uint32 pos) public view returns (Checkpoint memory) {
return _checkpoints[account][pos];
}
/**
* @inheritdoc IZeroExVotes
*/
function numCheckpoints(address account) public view returns (uint32) {
return SafeCast.toUint32(_checkpoints[account].length);
}
/**
* @inheritdoc IZeroExVotes
*/
function getVotes(address account) public view returns (uint256) {
unchecked {
uint256 pos = _checkpoints[account].length;
return pos == 0 ? 0 : _unsafeAccess(_checkpoints[account], pos - 1).votes;
}
}
/**
* @inheritdoc IZeroExVotes
*/
function getQuadraticVotes(address account) public view returns (uint256) {
unchecked {
uint256 pos = _checkpoints[account].length;
return pos == 0 ? 0 : _unsafeAccess(_checkpoints[account], pos - 1).quadraticVotes;
}
}
/**
* @inheritdoc IZeroExVotes
*/
function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) {
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
Checkpoint memory checkpoint = _checkpointsLookup(_checkpoints[account], blockNumber);
return checkpoint.votes;
}
/**
* @inheritdoc IZeroExVotes
*/
function getPastQuadraticVotes(address account, uint256 blockNumber) public view returns (uint256) {
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
Checkpoint memory checkpoint = _checkpointsLookup(_checkpoints[account], blockNumber);
return checkpoint.quadraticVotes;
}
/**
* @inheritdoc IZeroExVotes
*/
function getPastTotalSupply(uint256 blockNumber) public view returns (uint256) {
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
// Note that due to the disabled updates of `_totalSupplyCheckpoints` in `writeCheckpointTotalSupply` function
// this always returns 0.
Checkpoint memory checkpoint = _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
return checkpoint.votes;
}
/**
* @inheritdoc IZeroExVotes
*/
function getPastQuadraticTotalSupply(uint256 blockNumber) public view returns (uint256) {
require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
// Note that due to the disabled updates of `_totalSupplyCheckpoints` in `writeCheckpointTotalSupply` function
// this always returns 0.
Checkpoint memory checkpoint = _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
return checkpoint.quadraticVotes;
}
/**
* @inheritdoc IZeroExVotes
*/
function moveVotingPower(
address src,
address dst,
uint256 srcBalance,
uint256 dstBalance,
uint96 srcBalanceLastUpdated,
uint96 dstBalanceLastUpdated,
uint256 amount
) public virtual onlyToken returns (bool) {
if (src != dst) {
if (src != address(0)) {
(
uint256 oldWeight,
uint256 newWeight,
uint256 oldQuadraticWeight,
uint256 newQuadraticWeight
) = _writeCheckpoint(_checkpoints[src], _subtract, srcBalance, srcBalanceLastUpdated, amount);
emit DelegateVotesChanged(src, oldWeight, newWeight);
emit DelegateQuadraticVotesChanged(src, oldQuadraticWeight, newQuadraticWeight);
}
if (dst != address(0)) {
(
uint256 oldWeight,
uint256 newWeight,
uint256 oldQuadraticWeight,
uint256 newQuadraticWeight
) = _writeCheckpoint(_checkpoints[dst], _add, dstBalance, dstBalanceLastUpdated, amount);
emit DelegateVotesChanged(dst, oldWeight, newWeight);
emit DelegateQuadraticVotesChanged(dst, oldQuadraticWeight, newQuadraticWeight);
}
}
return true;
}
/**
* @inheritdoc IZeroExVotes
*/
function writeCheckpointTotalSupplyMint(
uint256 accountBalance,
uint256 amount
) public virtual onlyToken returns (bool) {
(, uint256 newWeight, , uint256 newQuadraticWeight) = _writeCheckpoint(
_totalSupplyCheckpoints,
_add,
accountBalance,
0,
amount
);
emit TotalSupplyChanged(newWeight, newQuadraticWeight);
return true;
}
/**
* @inheritdoc IZeroExVotes
*/
function writeCheckpointTotalSupplyBurn(
uint256 accountBalance,
uint256 amount
) public virtual onlyToken returns (bool) {
(, uint256 newWeight, , uint256 newQuadraticWeight) = _writeCheckpoint(
_totalSupplyCheckpoints,
_subtract,
accountBalance,
0,
amount
);
emit TotalSupplyChanged(newWeight, newQuadraticWeight);
return true;
}
/**
* @dev Lookup a value in a list of (sorted) checkpoints.
* Implementation as in openzeppelin/token/ERC20/extensions/ERC20Votes.sol except here we return the entire
* checkpoint rather than part of it
*/
function _checkpointsLookup(
Checkpoint[] storage ckpts,
uint256 blockNumber
) internal view returns (Checkpoint memory checkpoint) {
// We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
//
// Initially we check if the block is recent to narrow the search range.
// During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
// With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the
// invariant.
// - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
// - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
// Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
// out of bounds (in which case we're looking too far in the past and the result is 0).
// Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
// past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
// the same.
uint256 length = ckpts.length;
uint256 low = 0;
uint256 high = length;
if (length > 5) {
uint256 mid = length - Math.sqrt(length);
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
high = mid;
} else {
low = mid + 1;
}
}
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
high = mid;
} else {
low = mid + 1;
}
}
// Leaving here for posterity this is the original OZ implementation which we've replaced
// return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
if (high != 0) checkpoint = _unsafeAccess(ckpts, high - 1);
}
function _writeCheckpoint(
Checkpoint[] storage ckpts,
function(uint256, uint256) view returns (uint256) op,
uint256 userBalance,
uint96 balanceLastUpdated,
uint256 delta
)
internal
virtual
returns (uint256 oldWeight, uint256 newWeight, uint256 oldQuadraticWeight, uint256 newQuadraticWeight)
{
uint256 pos = ckpts.length;
Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0, 0) : _unsafeAccess(ckpts, pos - 1);
oldWeight = oldCkpt.votes;
newWeight = op(oldWeight, delta);
oldQuadraticWeight = oldCkpt.quadraticVotes;
// Remove the entire sqrt userBalance from quadratic voting power.
// Note that `userBalance` is value _after_ transfer.
if (pos > 0) {
uint256 oldQuadraticVotingPower = userBalance <= quadraticThreshold
? userBalance
: quadraticThreshold + Math.sqrt((userBalance - quadraticThreshold) * 1e18);
oldCkpt.quadraticVotes -= SafeCast.toUint96(oldQuadraticVotingPower);
}
// if wallet > threshold, calculate quadratic power over the treshold only, below threshold is linear
uint256 newBalance = op(userBalance, delta);
uint256 newQuadraticBalance = newBalance <= quadraticThreshold
? newBalance
: quadraticThreshold + Math.sqrt((newBalance - quadraticThreshold) * 1e18);
newQuadraticWeight = oldCkpt.quadraticVotes + newQuadraticBalance;
if (pos > 0 && oldCkpt.fromBlock == block.number) {
Checkpoint storage chpt = _unsafeAccess(ckpts, pos - 1);
chpt.votes = SafeCast.toUint96(newWeight);
chpt.quadraticVotes = SafeCast.toUint96(newQuadraticWeight);
} else {
ckpts.push(
Checkpoint({
fromBlock: SafeCast.toUint32(block.number),
votes: SafeCast.toUint96(newWeight),
quadraticVotes: SafeCast.toUint96(newQuadraticWeight)
})
);
}
}
function _add(uint256 a, uint256 b) private pure returns (uint256) {
return a + b;
}
function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
return a - b;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
* Implementation from openzeppelin/token/ERC20/extensions/ERC20Votes.sol
* https://github.com/ethereum/solidity/issues/9117
*/
function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) internal pure returns (Checkpoint storage result) {
assembly ("memory-safe") {
mstore(0, ckpts.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
function _checkSenderIsToken() private {
require(msg.sender == token, "ZeroExVotes: only token allowed");
}
}

View File

@ -1,167 +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.19;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import "@openzeppelin/token/ERC20/ERC20.sol";
import "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
import "./mocks/ZRXMock.sol";
import "../src/ZRXWrappedToken.sol";
import "../src/ZeroExVotes.sol";
import "../src/ZeroExTimelock.sol";
import "../src/ZeroExProtocolGovernor.sol";
import "../src/ZeroExTreasuryGovernor.sol";
contract BaseTest is Test {
address payable internal account1 = payable(vm.addr(1));
address payable internal account2 = payable(vm.addr(2));
address payable internal account3 = payable(vm.addr(3));
address payable internal account4 = payable(vm.addr(4));
address payable internal securityCouncil = payable(vm.addr(5));
uint256 internal quadraticThreshold = 1000000e18;
bytes32 internal constant DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
constructor() {
vm.deal(account1, 1e20);
vm.deal(account2, 1e20);
vm.deal(account3, 1e20);
vm.deal(account4, 1e20);
vm.deal(securityCouncil, 1e20);
}
function setupGovernance(
IERC20 zrxToken
) internal returns (ZRXWrappedToken, ZeroExVotes, ZeroExTimelock, ZeroExTimelock, address, address) {
(ZRXWrappedToken token, ZeroExVotes votes) = setupZRXWrappedToken(zrxToken);
vm.startPrank(account1);
address[] memory proposers = new address[](0);
address[] memory executors = new address[](0);
ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, account1);
ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
IVotes(address(votes)),
protocolTimelock,
securityCouncil
);
protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, account1);
ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
IVotes(address(votes)),
treasuryTimelock,
securityCouncil
);
treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
vm.stopPrank();
return (token, votes, protocolTimelock, treasuryTimelock, address(protocolGovernor), address(treasuryGovernor));
}
function setupZRXWrappedToken(IERC20 zrxToken) internal returns (ZRXWrappedToken, ZeroExVotes) {
vm.startPrank(account1);
address wTokenPrediction = predictAddress(account1, vm.getNonce(account1) + 2);
ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, quadraticThreshold);
ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
ZRXWrappedToken wToken = new ZRXWrappedToken(zrxToken, ZeroExVotes(address(votesProxy)));
vm.stopPrank();
assert(address(wToken) == wTokenPrediction);
return (wToken, ZeroExVotes(address(votesProxy)));
}
function mockZRXToken() internal returns (IERC20 zrxToken) {
vm.startPrank(account1);
bytes memory _bytecode = vm.getCode("./ZRXToken.json");
assembly {
zrxToken := create(0, add(_bytecode, 0x20), mload(_bytecode))
}
vm.stopPrank();
}
// Sourced from https://github.com/grappafinance/core/blob/master/src/test/utils/Utilities.sol
function predictAddress(address _origin, uint256 _nonce) public pure returns (address) {
if (_nonce == 0x00) {
return
address(
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80)))))
);
}
if (_nonce <= 0x7f) {
return
address(
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, uint8(_nonce)))))
);
}
if (_nonce <= 0xff) {
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(bytes1(0xd7), bytes1(0x94), _origin, bytes1(0x81), uint8(_nonce))
)
)
)
);
}
if (_nonce <= 0xffff) {
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(bytes1(0xd8), bytes1(0x94), _origin, bytes1(0x82), uint16(_nonce))
)
)
)
);
}
if (_nonce <= 0xffffff) {
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(bytes1(0xd9), bytes1(0x94), _origin, bytes1(0x83), uint24(_nonce))
)
)
)
);
}
return
address(
uint160(
uint256(
keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), _origin, bytes1(0x84), uint32(_nonce)))
)
)
);
}
}

View File

@ -1,454 +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.19;
import "@openzeppelin/token/ERC20/IERC20.sol";
import "../mocks/IZeroExMock.sol";
import "../mocks/IZrxTreasuryMock.sol";
import "../mocks/IStakingMock.sol";
import "../mocks/IZrxVaultMock.sol";
import "../BaseTest.t.sol";
import "../../src/ZRXWrappedToken.sol";
import "../../src/ZeroExVotes.sol";
import "../../src/ZeroExTimelock.sol";
import "../../src/ZeroExProtocolGovernor.sol";
import "../../src/ZeroExTreasuryGovernor.sol";
contract GovernanceE2ETest is BaseTest {
uint256 internal mainnetFork;
string internal MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
struct DelegatorPool {
address delegator;
bytes32 pool;
}
address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
address internal constant MATIC_TOKEN = 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0;
address internal constant WCELO_TOKEN = 0xE452E6Ea2dDeB012e20dB73bf5d3863A3Ac8d77a;
address internal constant WYV_TOKEN = 0x056017c55aE7AE32d12AeF7C679dF83A85ca75Ff;
address internal constant EXCHANGE_PROXY = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
address internal constant EXCHANGE_GOVERNOR = 0x618F9C67CE7Bf1a50afa1E7e0238422601b0ff6e;
address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
address internal constant STAKING = 0xa26e80e7Dea86279c6d778D702Cc413E6CFfA777; // Holds ~$262K in WETH for rewards
address internal constant ZRX_VAULT = 0xBa7f8b5fB1b19c1211c5d49550fcD149177A5Eaf; // Holds ~$10m in staked ZRX
address internal constant STAKING_AND_VAULT_OWNER = 0x7D3455421BbC5Ed534a83c88FD80387dc8271392;
address internal staker1 = 0x885c327cAD2aebb969dfaAb4c928B73CA17e3887;
address internal staker2 = 0x03c823e96F6964076C118395F08a2D7edF0f8a8C;
address[] internal topStakers = [
0x5775afA796818ADA27b09FaF5c90d101f04eF600,
0xE1bdcd3B70e077D2d66ADcbe78be3941F0BF380B,
0xcCa71809E8870AFEB72c4720d0fe50d5C3230e05,
0x828FD91d3e3a9FFa6305e78B9aE2Cfbc5B5D9f6B,
0x4A36C3DA5d367B148d17265e7d7feafcf8fb4a21,
0xEeff6fd32DeaFe1a9d3258A51c7F952F9FF0B2Ce,
0x1D0738b927dFCBFBD59A9F0944BbD1860d3B9248,
0x0C073E7248C1b548a08b27dD3af5D0f39c774280,
0xA178FF321335BB777A7E21A56376592F69556b9c,
0xD06CfBb59d2e8918F84D99d981039d7706DCA288
];
// voting power 1500000e18
address internal voter1 = 0x292c6DAE7417B3D31d8B6e1d2EeA0258d14C4C4b;
bytes32 internal voter1Pool = 0x0000000000000000000000000000000000000000000000000000000000000030;
bytes32[] internal voter1_operated_poolIds = [voter1Pool];
// voting power 1500000.5e18
address internal voter2 = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
bytes32 internal voter2Pool = 0x0000000000000000000000000000000000000000000000000000000000000031;
bytes32[] internal voter2_operated_poolIds = [voter2Pool];
// voting power 1500000e18
address internal voter3 = 0x5265Bde27F57E738bE6c1F6AB3544e82cdc92a8f;
bytes32 internal voter3Pool = 0x0000000000000000000000000000000000000000000000000000000000000032;
bytes32[] internal voter3_operated_poolIds = [voter3Pool];
// voting power 1500000e18
address internal voter4 = 0xcA9F5049c1Ea8FC78574f94B7Cf5bE5fEE354C31;
bytes32 internal voter4Pool = 0x0000000000000000000000000000000000000000000000000000000000000034;
bytes32[] internal voter4_operated_poolIds = [voter4Pool];
// voting power 1500000e18
address internal voter5 = 0xDBB5664a9DBCB98F6365804880e5b277B3155422;
bytes32 internal voter5Pool = 0x0000000000000000000000000000000000000000000000000000000000000035;
bytes32[] internal voter5_operated_poolIds = [voter5Pool];
// voting power 2291490.952353335e18
address internal voter6 = 0x9a4Eb1101C0c053505Bd71d2fFa27Ed902DEaD85;
bytes32 internal voter6Pool = 0x0000000000000000000000000000000000000000000000000000000000000029;
bytes32[] internal voter6_operated_poolIds = [voter6Pool];
// voting power 4575984.325e18
address internal voter7 = 0x9564177EC8052C92752a488a71769F710aA0A41D;
bytes32 internal voter7Pool = 0x0000000000000000000000000000000000000000000000000000000000000025;
bytes32[] internal voter7_operated_poolIds = [voter7Pool];
IERC20 internal token;
IERC20 internal maticToken;
IERC20 internal wceloToken;
IERC20 internal wyvToken;
IZeroExMock internal exchange;
IZrxTreasuryMock internal treasury;
IZrxVaultMock internal vault;
IStakingMock internal staking;
IERC20 internal weth;
ZRXWrappedToken internal wToken;
ZeroExVotes internal votes;
ZeroExTimelock internal protocolTimelock;
ZeroExTimelock internal treasuryTimelock;
ZeroExProtocolGovernor internal protocolGovernor;
ZeroExTreasuryGovernor internal treasuryGovernor;
function setUp() public {
mainnetFork = vm.createFork(MAINNET_RPC_URL);
vm.selectFork(mainnetFork);
token = IERC20(ZRX_TOKEN);
maticToken = IERC20(MATIC_TOKEN);
wceloToken = IERC20(WCELO_TOKEN);
wyvToken = IERC20(WYV_TOKEN);
exchange = IZeroExMock(payable(EXCHANGE_PROXY));
treasury = IZrxTreasuryMock(TREASURY);
vault = IZrxVaultMock(ZRX_VAULT);
staking = IStakingMock(STAKING);
weth = IERC20(staking.getWethContract());
address protocolGovernorAddress;
address treasuryGovernorAddress;
(
wToken,
votes,
protocolTimelock,
treasuryTimelock,
protocolGovernorAddress,
treasuryGovernorAddress
) = setupGovernance(token);
protocolGovernor = ZeroExProtocolGovernor(payable(protocolGovernorAddress));
treasuryGovernor = ZeroExTreasuryGovernor(payable(treasuryGovernorAddress));
}
function testProtocolGovernanceMigration() public {
// initially the zrx exchange is owned by the legacy exchange governor
assertEq(exchange.owner(), EXCHANGE_GOVERNOR);
// transfer ownership to new protocol governor
vm.prank(EXCHANGE_GOVERNOR);
exchange.transferOwnership(address(protocolGovernor));
assertEq(exchange.owner(), address(protocolGovernor));
}
function testTreasuryGovernanceMigration() public {
// Create a proposal to migrate to new governor
uint256 currentEpoch = staking.currentEpoch();
uint256 executionEpoch = currentEpoch + 2;
vm.startPrank(voter3);
IZrxTreasuryMock.ProposedAction[] memory actions = new IZrxTreasuryMock.ProposedAction[](4);
// Transfer MATIC
uint256 maticBalance = maticToken.balanceOf(address(treasury));
actions[0] = IZrxTreasuryMock.ProposedAction({
target: MATIC_TOKEN,
data: abi.encodeCall(maticToken.transfer, (address(treasuryGovernor), maticBalance)),
value: 0
});
// Transfer ZRX
uint256 zrxBalance = token.balanceOf(address(treasury));
actions[1] = IZrxTreasuryMock.ProposedAction({
target: ZRX_TOKEN,
data: abi.encodeCall(token.transfer, (address(treasuryGovernor), zrxBalance)),
value: 0
});
// Transfer wCELO
uint256 wceloBalance = wceloToken.balanceOf(address(treasury));
actions[2] = IZrxTreasuryMock.ProposedAction({
target: WCELO_TOKEN,
data: abi.encodeCall(wceloToken.transfer, (address(treasuryGovernor), wceloBalance)),
value: 0
});
// Transfer WYV
uint256 wyvBalance = wyvToken.balanceOf(address(treasury));
actions[3] = IZrxTreasuryMock.ProposedAction({
target: WYV_TOKEN,
data: abi.encodeCall(wyvToken.transfer, (address(treasuryGovernor), wyvBalance)),
value: 0
});
uint256 proposalId = treasury.propose(
actions,
executionEpoch,
"Z-5 Migrate to new treasury governor",
voter3_operated_poolIds
);
// Once a proposal is created, it becomes open for voting at the epoch after next (currentEpoch + 2)
// and is open for the voting period (currently set to 3 days).
uint256 epochDurationInSeconds = staking.epochDurationInSeconds(); // Currently set to 604800 seconds = 7 days
uint256 currentEpochEndTime = staking.currentEpochStartTimeInSeconds() + epochDurationInSeconds;
vm.warp(currentEpochEndTime + 1);
staking.endEpoch();
vm.warp(block.timestamp + epochDurationInSeconds + 1);
staking.endEpoch();
vm.stopPrank();
// quorum is 10,000,000e18 so reach that via the following votes
vm.prank(voter1);
treasury.castVote(proposalId, true, voter1_operated_poolIds);
vm.stopPrank();
vm.prank(voter2);
treasury.castVote(proposalId, true, voter2_operated_poolIds);
vm.stopPrank();
vm.prank(voter3);
treasury.castVote(proposalId, true, voter3_operated_poolIds);
vm.stopPrank();
vm.prank(voter4);
treasury.castVote(proposalId, true, voter4_operated_poolIds);
vm.stopPrank();
vm.prank(voter5);
treasury.castVote(proposalId, true, voter5_operated_poolIds);
vm.stopPrank();
vm.prank(voter6);
treasury.castVote(proposalId, true, voter6_operated_poolIds);
vm.stopPrank();
vm.prank(voter7);
treasury.castVote(proposalId, true, voter7_operated_poolIds);
vm.stopPrank();
vm.warp(block.timestamp + 3 days + 1);
// Execute proposal
treasury.execute(proposalId, actions);
// Assert value of treasury has correctly transferred
uint256 maticBalanceNewTreasury = maticToken.balanceOf(address(treasuryGovernor));
assertEq(maticBalanceNewTreasury, maticBalance);
uint256 zrxBalanceNewTreasury = token.balanceOf(address(treasuryGovernor));
assertEq(zrxBalanceNewTreasury, zrxBalance);
uint256 wceloBalanceNewTreasury = wceloToken.balanceOf(address(treasuryGovernor));
assertEq(wceloBalanceNewTreasury, wceloBalance);
uint256 wyvBalanceNewTreasury = wyvToken.balanceOf(address(treasuryGovernor));
assertEq(wyvBalanceNewTreasury, wyvBalance);
}
// Test entering catastrophic failure mode on the zrx vault to decomission v3 staking
function testCatastrophicFailureModeOnStaking() public {
DelegatorPool[5] memory delegatorPools = [
DelegatorPool(
0x0ee1F33A2EB0da738FdF035C48d62d75e996a3bd,
0x0000000000000000000000000000000000000000000000000000000000000016
),
DelegatorPool(
0xcAb3d8cBBb3dA1bDabfB003B9C828B27a821717f,
0x0000000000000000000000000000000000000000000000000000000000000017
),
DelegatorPool(
0x7f88b00Db27a500fBfA7EbC9c3CaA2Dea6F59d5b,
0x0000000000000000000000000000000000000000000000000000000000000014
),
DelegatorPool(
0xcE266E6123B682f7A7388097e2155b5379D9AC78,
0x0000000000000000000000000000000000000000000000000000000000000014
),
DelegatorPool(
0xBa4f44E774158408E2DC6c5cb65BC995F0a89180, // pool operator
0x0000000000000000000000000000000000000000000000000000000000000017
)
];
// Enter catastrophic failure mode on the zrx vault
vm.prank(STAKING_AND_VAULT_OWNER);
vault.enterCatastrophicFailure();
vm.stopPrank();
// Stakes can still be withdrawn
// staker1 withdraws
uint256 stake1 = vault.balanceOf(staker1);
uint256 balance1 = token.balanceOf(staker1);
assertGt(stake1, 0);
vm.prank(staker1);
vault.withdrawAllFrom(staker1);
vm.stopPrank();
assertEq(vault.balanceOf(staker1), 0);
assertEq(token.balanceOf(staker1), stake1 + balance1);
// staker2 withdraws
uint256 stake2 = vault.balanceOf(staker2);
uint256 balance2 = token.balanceOf(staker2);
assertGt(stake2, 0);
vm.prank(staker2);
vault.withdrawAllFrom(staker2);
vm.stopPrank();
assertEq(vault.balanceOf(staker2), 0);
assertEq(token.balanceOf(staker2), stake2 + balance2);
// Test top stakers can withdraw
for (uint256 i = 0; i < topStakers.length; i++) {
address staker = topStakers[i];
uint256 stake = vault.balanceOf(staker);
uint256 balance = token.balanceOf(staker);
assertGt(stake, 0);
vm.prank(staker);
vault.withdrawAllFrom(staker);
vm.stopPrank();
assertEq(vault.balanceOf(staker), 0);
assertEq(token.balanceOf(staker), stake + balance);
}
// Delegator can withdraw rewards
for (uint256 i = 0; i < delegatorPools.length; i++) {
address delegator = delegatorPools[i].delegator;
bytes32 pool = delegatorPools[i].pool;
uint256 reward = staking.computeRewardBalanceOfDelegator(pool, delegator);
assertGt(reward, 0);
uint256 balanceBeforeReward = weth.balanceOf(delegator);
vm.prank(delegator);
staking.withdrawDelegatorRewards(pool);
vm.stopPrank();
assertEq(weth.balanceOf(delegator), balanceBeforeReward + reward);
}
}
function testSwitchDelegationInCatastrophicMode() public {
// Enter catastrophic failure mode on the zrx vault
vm.prank(STAKING_AND_VAULT_OWNER);
vault.enterCatastrophicFailure();
// 0x delegator
address delegator = 0x5775afA796818ADA27b09FaF5c90d101f04eF600;
uint256 stake = vault.balanceOf(delegator);
uint256 balance = token.balanceOf(delegator);
assertGt(stake, 0);
// Withdraw stake all at once
vm.startPrank(delegator);
vault.withdrawAllFrom(delegator);
assertEq(vault.balanceOf(delegator), 0);
assertEq(token.balanceOf(delegator), stake + balance);
// delegate 1M ZRX to 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08
vm.roll(block.number + 1);
address delegate = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
uint256 amountToDelegate = 1000000e18;
// Approve the wrapped token and deposit 1m ZRX
token.approve(address(wToken), amountToDelegate);
wToken.depositFor(delegator, amountToDelegate);
assertEq(wToken.balanceOf(delegator), amountToDelegate);
vm.roll(block.number + 1);
wToken.delegate(delegate);
vm.stopPrank();
assertEq(votes.getVotes(delegate), amountToDelegate);
assertEq(votes.getQuadraticVotes(delegate), amountToDelegate);
}
function testSwitchDelegationInNormalOperationMode() public {
// 0x delegator
address delegator = 0x5775afA796818ADA27b09FaF5c90d101f04eF600;
uint256 balance = token.balanceOf(delegator);
// Undelegate stake from pool 0x35
vm.startPrank(delegator);
staking.moveStake(
IStructs.StakeInfo(
IStructs.StakeStatus.DELEGATED,
0x0000000000000000000000000000000000000000000000000000000000000035
),
IStructs.StakeInfo(IStructs.StakeStatus.UNDELEGATED, bytes32(0)),
3000000000000000000000000
);
// Undelegate stake from pool 0x38
IStructs.StoredBalance memory storedBalance38 = staking.getStakeDelegatedToPoolByOwner(
delegator,
0x0000000000000000000000000000000000000000000000000000000000000038
);
staking.moveStake(
IStructs.StakeInfo(
IStructs.StakeStatus.DELEGATED,
0x0000000000000000000000000000000000000000000000000000000000000038
),
IStructs.StakeInfo(IStructs.StakeStatus.UNDELEGATED, bytes32(0)),
storedBalance38.currentEpochBalance
);
// Warp past an epochs and unstake
uint256 epochEndTime = staking.getCurrentEpochEarliestEndTimeInSeconds();
vm.warp(epochEndTime + 1);
staking.endEpoch();
staking.unstake(6000000000000000000000000);
vm.stopPrank();
assertEq(token.balanceOf(delegator), balance + 2 * 3000000000000000000000000);
// delegate 1M ZRX to 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08
vm.roll(block.number + 1);
address delegate = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
uint256 amountToDelegate = 1000000e18;
// Approve the wrapped token and deposit 1m ZRX
token.approve(address(wToken), amountToDelegate);
wToken.depositFor(delegator, amountToDelegate);
assertEq(wToken.balanceOf(delegator), amountToDelegate);
vm.roll(block.number + 1);
wToken.delegate(delegate);
vm.stopPrank();
assertEq(votes.getVotes(delegate), amountToDelegate);
assertEq(votes.getQuadraticVotes(delegate), amountToDelegate);
}
}

View File

@ -1,21 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library CubeRoot {
/// @dev Returns the cube root of `x`.
/// Credit to pleasemarkdarkly under MIT license
// Originaly from https://github.com/pleasemarkdarkly/fei-protocol-core-hh/blob/main/contracts/utils/Roots.sol
function cbrt(uint y) internal pure returns (uint z) {
// Newton's method https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
if (y > 7) {
z = y;
uint x = y / 3 + 1;
while (x < z) {
z = x;
x = (y / (x * x) + (2 * x)) / 3;
}
} else if (y != 0) {
z = 1;
}
}
}

View File

@ -1,36 +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.19;
import "@0x/contracts-utils/contracts/src/v08/interfaces/IOwnableV08.sol";
/// @dev Owner management and migration features.
interface IOwnableFeature is IOwnableV08 {
/// @dev Emitted when `migrate()` is called.
/// @param caller The caller of `migrate()`.
/// @param migrator The migration contract.
/// @param newOwner The address of the new owner.
event Migrated(address caller, address migrator, address newOwner);
/// @dev Execute a migration function in the context of the ZeroEx contract.
/// The result of the function being called should be the magic bytes
/// 0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner.
/// The owner will be temporarily set to `address(this)` inside the call.
/// Before returning, the owner will be set to `newOwner`.
/// @param target The migrator contract address.
/// @param newOwner The address of the new owner.
/// @param data The call data.
function migrate(address target, bytes calldata data, address newOwner) external;
}

View File

@ -1,48 +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.19;
pragma experimental ABIEncoderV2;
/// @dev Basic registry management features.
interface ISimpleFunctionRegistryFeature {
/// @dev A function implementation was updated via `extend()` or `rollback()`.
/// @param selector The function selector.
/// @param oldImpl The implementation contract address being replaced.
/// @param newImpl The replacement implementation contract address.
event ProxyFunctionUpdated(bytes4 indexed selector, address oldImpl, address newImpl);
/// @dev Roll back to a prior implementation of a function.
/// @param selector The function selector.
/// @param targetImpl The address of an older implementation of the function.
function rollback(bytes4 selector, address targetImpl) external;
/// @dev Register or replace a function.
/// @param selector The function selector.
/// @param impl The implementation contract for the function.
function extend(bytes4 selector, address impl) external;
/// @dev Retrieve the length of the rollback history for a function.
/// @param selector The function selector.
/// @return rollbackLength The number of items in the rollback history for
/// the function.
function getRollbackLength(bytes4 selector) external view returns (uint256 rollbackLength);
/// @dev Retrieve an entry in the rollback history for a function.
/// @param selector The function selector.
/// @param idx The index in the rollback history.
/// @return impl An implementation address for the function at
/// index `idx`.
function getRollbackEntryAtIndex(bytes4 selector, uint256 idx) external view returns (address impl);
}

View File

@ -1,196 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import "./IZrxVaultMock.sol";
import "./IStructs.sol";
import "./IStorageMock.sol";
pragma solidity ^0.8.19;
interface IStakingMock is IStorageMock {
/// @dev Adds a new exchange address
/// @param addr Address of exchange contract to add
function addExchangeAddress(address addr) external;
/// @dev Create a new staking pool. The sender will be the operator of this pool.
/// Note that an operator must be payable.
/// @param operatorShare Portion of rewards owned by the operator, in ppm.
/// @param addOperatorAsMaker Adds operator to the created pool as a maker for convenience iff true.
/// @return poolId The unique pool id generated for this pool.
function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker) external returns (bytes32 poolId);
/// @dev Decreases the operator share for the given pool (i.e. increases pool rewards for members).
/// @param poolId Unique Id of pool.
/// @param newOperatorShare The newly decreased percentage of any rewards owned by the operator.
function decreaseStakingPoolOperatorShare(bytes32 poolId, uint32 newOperatorShare) external;
/// @dev Begins a new epoch, preparing the prior one for finalization.
/// Throws if not enough time has passed between epochs or if the
/// previous epoch was not fully finalized.
/// @return numPoolsToFinalize The number of unfinalized pools.
function endEpoch() external returns (uint256);
/// @dev Instantly finalizes a single pool that earned rewards in the previous
/// epoch, crediting it rewards for members and withdrawing operator's
/// rewards as WETH. This can be called by internal functions that need
/// to finalize a pool immediately. Does nothing if the pool is already
/// finalized or did not earn rewards in the previous epoch.
/// @param poolId The pool ID to finalize.
function finalizePool(bytes32 poolId) external;
/// @dev Initialize storage owned by this contract.
/// This function should not be called directly.
/// The StakingProxy contract will call it in `attachStakingContract()`.
function init() external;
/// @dev Allows caller to join a staking pool as a maker.
/// @param poolId Unique id of pool.
function joinStakingPoolAsMaker(bytes32 poolId) external;
/// @dev Moves stake between statuses: 'undelegated' or 'delegated'.
/// Delegated stake can also be moved between pools.
/// This change comes into effect next epoch.
/// @param from status to move stake out of.
/// @param to status to move stake into.
/// @param amount of stake to move.
function moveStake(IStructs.StakeInfo calldata from, IStructs.StakeInfo calldata to, uint256 amount) external;
/// @dev Pays a protocol fee in ETH.
/// @param makerAddress The address of the order's maker.
/// @param payerAddress The address that is responsible for paying the protocol fee.
/// @param protocolFee The amount of protocol fees that should be paid.
function payProtocolFee(address makerAddress, address payerAddress, uint256 protocolFee) external payable;
/// @dev Removes an existing exchange address
/// @param addr Address of exchange contract to remove
function removeExchangeAddress(address addr) external;
/// @dev Set all configurable parameters at once.
/// @param _epochDurationInSeconds Minimum seconds between epochs.
/// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
/// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
/// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
/// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor.
function setParams(
uint256 _epochDurationInSeconds,
uint32 _rewardDelegatedStakeWeight,
uint256 _minimumPoolStake,
uint32 _cobbDouglasAlphaNumerator,
uint32 _cobbDouglasAlphaDenominator
) external;
/// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault.
/// Unstake to retrieve the ZRX. Stake is in the 'Active' status.
/// @param amount of ZRX to stake.
function stake(uint256 amount) external;
/// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to
/// the staker. Stake must be in the 'undelegated' status in both the
/// current and next epoch in order to be unstaked.
/// @param amount of ZRX to unstake.
function unstake(uint256 amount) external;
/// @dev Withdraws the caller's WETH rewards that have accumulated
/// until the last epoch.
/// @param poolId Unique id of pool.
function withdrawDelegatorRewards(bytes32 poolId) external;
/// @dev Computes the reward balance in ETH of a specific member of a pool.
/// @param poolId Unique id of pool.
/// @param member The member of the pool.
/// @return reward Balance in ETH.
function computeRewardBalanceOfDelegator(bytes32 poolId, address member) external view returns (uint256 reward);
/// @dev Computes the reward balance in ETH of the operator of a pool.
/// @param poolId Unique id of pool.
/// @return reward Balance in ETH.
function computeRewardBalanceOfOperator(bytes32 poolId) external view returns (uint256 reward);
/// @dev Returns the earliest end time in seconds of this epoch.
/// The next epoch can begin once this time is reached.
/// Epoch period = [startTimeInSeconds..endTimeInSeconds)
/// @return Time in seconds.
function getCurrentEpochEarliestEndTimeInSeconds() external view returns (uint256);
/// @dev Gets global stake for a given status.
/// @param stakeStatus UNDELEGATED or DELEGATED
/// @return balance Global stake for given status.
function getGlobalStakeByStatus(
IStructs.StakeStatus stakeStatus
) external view returns (IStructs.StoredBalance memory balance);
/// @dev Gets an owner's stake balances by status.
/// @param staker Owner of stake.
/// @param stakeStatus UNDELEGATED or DELEGATED
/// @return balance Owner's stake balances for given status.
function getOwnerStakeByStatus(
address staker,
IStructs.StakeStatus stakeStatus
) external view returns (IStructs.StoredBalance memory balance);
/// @dev Retrieves all configurable parameter values.
/// @return _epochDurationInSeconds Minimum seconds between epochs.
/// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
/// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
/// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
/// @return _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor.
function getParams()
external
view
returns (
uint256 _epochDurationInSeconds,
uint32 _rewardDelegatedStakeWeight,
uint256 _minimumPoolStake,
uint32 _cobbDouglasAlphaNumerator,
uint32 _cobbDouglasAlphaDenominator
);
/// @param staker of stake.
/// @param poolId Unique Id of pool.
/// @return balance Stake delegated to pool by staker.
function getStakeDelegatedToPoolByOwner(
address staker,
bytes32 poolId
) external view returns (IStructs.StoredBalance memory balance);
/// @dev Returns a staking pool
/// @param poolId Unique id of pool.
function getStakingPool(bytes32 poolId) external view returns (IStructs.Pool memory);
/// @dev Get stats on a staking pool in this epoch.
/// @param poolId Pool Id to query.
/// @return PoolStats struct for pool id.
function getStakingPoolStatsThisEpoch(bytes32 poolId) external view returns (IStructs.PoolStats memory);
/// @dev Returns the total stake delegated to a specific staking pool,
/// across all members.
/// @param poolId Unique Id of pool.
/// @return balance Total stake delegated to pool.
function getTotalStakeDelegatedToPool(bytes32 poolId) external view returns (IStructs.StoredBalance memory balance);
/// @dev An overridable way to access the deployed WETH contract.
/// Must be view to allow overrides to access state.
/// @return wethContract The WETH contract instance.
function getWethContract() external view returns (address wethContract);
/// @dev An overridable way to access the deployed zrxVault.
/// Must be view to allow overrides to access state.
/// @return zrxVault The zrxVault contract.
function getZrxVault() external view returns (IZrxVaultMock zrxVault);
}

View File

@ -1,49 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.19;
import "./IZrxVaultMock.sol";
import "./IStructs.sol";
interface IStorageMock {
function stakingContract() external view returns (address);
function lastPoolId() external view returns (bytes32);
function numMakersByPoolId(bytes32 poolId) external view returns (uint256);
function currentEpoch() external view returns (uint256);
function currentEpochStartTimeInSeconds() external view returns (uint256);
function protocolFeesThisEpochByPool(bytes32 poolId) external view returns (uint256);
function validExchanges(address exchangeAddress) external view returns (bool);
function epochDurationInSeconds() external view returns (uint256);
function rewardDelegatedStakeWeight() external view returns (uint32);
function minimumPoolStake() external view returns (uint256);
function cobbDouglasAlphaNumerator() external view returns (uint32);
function cobbDouglasAlphaDenominator() external view returns (uint32);
}

View File

@ -1,92 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.19;
interface IStructs {
/// @dev Stats for a pool that earned rewards.
/// @param feesCollected Fees collected in ETH by this pool.
/// @param weightedStake Amount of weighted stake in the pool.
/// @param membersStake Amount of non-operator stake in the pool.
struct PoolStats {
uint256 feesCollected;
uint256 weightedStake;
uint256 membersStake;
}
/// @dev Holds stats aggregated across a set of pools.
/// @param rewardsAvailable Rewards (ETH) available to the epoch
/// being finalized (the previous epoch). This is simply the balance
/// of the contract at the end of the epoch.
/// @param numPoolsToFinalize The number of pools that have yet to be finalized through `finalizePools()`.
/// @param totalFeesCollected The total fees collected for the epoch being finalized.
/// @param totalWeightedStake The total fees collected for the epoch being finalized.
/// @param totalRewardsFinalized Amount of rewards that have been paid during finalization.
struct AggregatedStats {
uint256 rewardsAvailable;
uint256 numPoolsToFinalize;
uint256 totalFeesCollected;
uint256 totalWeightedStake;
uint256 totalRewardsFinalized;
}
/// @dev Encapsulates a balance for the current and next epochs.
/// Note that these balances may be stale if the current epoch
/// is greater than `currentEpoch`.
/// @param currentEpoch the current epoch
/// @param currentEpochBalance balance in the current epoch.
/// @param nextEpochBalance balance in `currentEpoch+1`.
struct StoredBalance {
uint64 currentEpoch;
uint96 currentEpochBalance;
uint96 nextEpochBalance;
}
/// @dev Statuses that stake can exist in.
/// Any stake can be (re)delegated effective at the next epoch
/// Undelegated stake can be withdrawn if it is available in both the current and next epoch
enum StakeStatus {
UNDELEGATED,
DELEGATED
}
/// @dev Info used to describe a status.
/// @param status of the stake.
/// @param poolId Unique Id of pool. This is set when status=DELEGATED.
struct StakeInfo {
StakeStatus status;
bytes32 poolId;
}
/// @dev Struct to represent a fraction.
/// @param numerator of fraction.
/// @param denominator of fraction.
struct Fraction {
uint256 numerator;
uint256 denominator;
}
/// @dev Holds the metadata for a staking pool.
/// @param operator of the pool.
/// @param operatorShare Fraction of the total balance owned by the operator, in ppm.
struct Pool {
address operator;
uint32 operatorShare;
}
}

View File

@ -1,24 +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.19;
import "./IOwnableFeature.sol";
import "./ISimpleFunctionRegistryFeature.sol";
/// @dev Minimal viable Exchange Proxy interface for governance use.
interface IZeroExMock is IOwnableFeature, ISimpleFunctionRegistryFeature {
/// @dev Fallback for just receiving ether.
receive() external payable;
}

View File

@ -1,159 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.19;
import "./IStakingMock.sol";
/// @dev Minimal viable Treasury interface for governance use.
interface IZrxTreasuryMock {
struct TreasuryParameters {
uint256 votingPeriod;
uint256 proposalThreshold;
uint256 quorumThreshold;
bytes32 defaultPoolId;
}
struct ProposedAction {
address target;
bytes data;
uint256 value;
}
struct Proposal {
bytes32 actionsHash;
uint256 executionEpoch;
uint256 voteEpoch;
uint256 votesFor;
uint256 votesAgainst;
bool executed;
}
event ProposalCreated(
address proposer,
bytes32[] operatedPoolIds,
uint256 proposalId,
ProposedAction[] actions,
uint256 executionEpoch,
string description
);
event VoteCast(address voter, bytes32[] operatedPoolIds, uint256 proposalId, bool support, uint256 votingPower);
event ProposalExecuted(uint256 proposalId);
function stakingProxy() external view returns (IStakingMock);
function defaultPoolId() external view returns (bytes32);
function votingPeriod() external view returns (uint256);
function proposalThreshold() external view returns (uint256);
function quorumThreshold() external view returns (uint256);
/// @dev Updates the proposal and quorum thresholds to the given
/// values. Note that this function is only callable by the
/// treasury contract itself, so the threshold can only be
/// updated via a successful treasury proposal.
/// @param newProposalThreshold The new value for the proposal threshold.
/// @param newQuorumThreshold The new value for the quorum threshold.
function updateThresholds(uint256 newProposalThreshold, uint256 newQuorumThreshold) external;
/// @dev Creates a proposal to send ZRX from this treasury on the
/// the given actions. Must have at least `proposalThreshold`
/// of voting power to call this function. See `getVotingPower`
/// for how voting power is computed. If a proposal is successfully
/// created, voting starts at the epoch after next (currentEpoch + 2).
/// If the vote passes, the proposal is executable during the
/// `executionEpoch`. See `hasProposalPassed` for the passing criteria.
/// @param actions The proposed ZRX actions. An action specifies a
/// contract call.
/// @param executionEpoch The epoch during which the proposal is to
/// be executed if it passes. Must be at least two epochs
/// from the current epoch.
/// @param description A text description for the proposal.
/// @param operatedPoolIds The pools operated by `msg.sender`. The
/// ZRX currently delegated to those pools will be accounted
/// for in the voting power.
/// @return proposalId The ID of the newly created proposal.
function propose(
ProposedAction[] calldata actions,
uint256 executionEpoch,
string calldata description,
bytes32[] calldata operatedPoolIds
) external returns (uint256 proposalId);
/// @dev Casts a vote for the given proposal. Only callable
/// during the voting period for that proposal.
/// One address can only vote once.
/// See `getVotingPower` for how voting power is computed.
/// @param proposalId The ID of the proposal to vote on.
/// @param support Whether to support the proposal or not.
/// @param operatedPoolIds The pools operated by `msg.sender`. The
/// ZRX currently delegated to those pools will be accounted
/// for in the voting power.
function castVote(uint256 proposalId, bool support, bytes32[] calldata operatedPoolIds) external;
/// @dev Casts a vote for the given proposal, by signature.
/// Only callable during the voting period for that proposal.
/// One address/voter can only vote once.
/// See `getVotingPower` for how voting power is computed.
/// @param proposalId The ID of the proposal to vote on.
/// @param support Whether to support the proposal or not.
/// @param operatedPoolIds The pools operated by the signer. The
/// ZRX currently delegated to those pools will be accounted
/// for in the voting power.
/// @param v the v field of the signature
/// @param r the r field of the signature
/// @param s the s field of the signature
function castVoteBySignature(
uint256 proposalId,
bool support,
bytes32[] memory operatedPoolIds,
uint8 v,
bytes32 r,
bytes32 s
) external;
/// @dev Executes a proposal that has passed and is
/// currently executable.
/// @param proposalId The ID of the proposal to execute.
/// @param actions Actions associated with the proposal to execute.
function execute(uint256 proposalId, ProposedAction[] memory actions) external payable;
/// @dev Returns the total number of proposals.
/// @return count The number of proposals.
function proposalCount() external view returns (uint256 count);
/// @dev Computes the current voting power of the given account.
/// Voting power is equal to:
/// (ZRX delegated to the default pool) +
/// 0.5 * (ZRX delegated to other pools) +
/// 0.5 * (ZRX delegated to pools operated by account)
/// @param account The address of the account.
/// @param operatedPoolIds The pools operated by `account`. The
/// ZRX currently delegated to those pools will be accounted
/// for in the voting power.
/// @return votingPower The current voting power of the given account.
function getVotingPower(
address account,
bytes32[] calldata operatedPoolIds
) external view returns (uint256 votingPower);
}

View File

@ -1,83 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.19;
interface IZrxVaultMock {
/// @dev Emmitted whenever a StakingProxy is set in a vault.
event StakingProxySet(address stakingProxyAddress);
/// @dev Emitted when the Staking contract is put into Catastrophic Failure Mode
/// @param sender Address of sender (`msg.sender`)
event InCatastrophicFailureMode(address sender);
/// @dev Emitted when Zrx Tokens are deposited into the vault.
/// @param staker of Zrx Tokens.
/// @param amount of Zrx Tokens deposited.
event Deposit(address indexed staker, uint256 amount);
/// @dev Emitted when Zrx Tokens are withdrawn from the vault.
/// @param staker of Zrx Tokens.
/// @param amount of Zrx Tokens withdrawn.
event Withdraw(address indexed staker, uint256 amount);
/// @dev Emitted whenever the ZRX AssetProxy is set.
event ZrxProxySet(address zrxProxyAddress);
/// @dev Sets the address of the StakingProxy contract.
/// Note that only the contract staker can call this function.
/// @param _stakingProxyAddress Address of Staking proxy contract.
function setStakingProxy(address _stakingProxyAddress) external;
/// @dev Vault enters into Catastrophic Failure Mode.
/// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! ***
/// Note that only the contract staker can call this function.
function enterCatastrophicFailure() external;
/// @dev Sets the Zrx proxy.
/// Note that only the contract staker can call this.
/// Note that this can only be called when *not* in Catastrophic Failure mode.
/// @param zrxProxyAddress Address of the 0x Zrx Proxy.
function setZrxProxy(address zrxProxyAddress) external;
/// @dev Deposit an `amount` of Zrx Tokens from `staker` into the vault.
/// Note that only the Staking contract can call this.
/// Note that this can only be called when *not* in Catastrophic Failure mode.
/// @param staker of Zrx Tokens.
/// @param amount of Zrx Tokens to deposit.
function depositFrom(address staker, uint256 amount) external;
/// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault.
/// Note that only the Staking contract can call this.
/// Note that this can only be called when *not* in Catastrophic Failure mode.
/// @param staker of Zrx Tokens.
/// @param amount of Zrx Tokens to withdraw.
function withdrawFrom(address staker, uint256 amount) external;
/// @dev Withdraw ALL Zrx Tokens to `staker` from the vault.
/// Note that this can only be called when *in* Catastrophic Failure mode.
/// @param staker of Zrx Tokens.
function withdrawAllFrom(address staker) external returns (uint256);
/// @dev Returns the balance in Zrx Tokens of the `staker`
/// @return Balance in Zrx.
function balanceOf(address staker) external view returns (uint256);
/// @dev Returns the entire balance of Zrx tokens in the vault.
function balanceOfZrxVault() external view returns (uint256);
}

View File

@ -1,31 +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.19;
import "forge-std/Test.sol";
import "@openzeppelin/token/ERC20/ERC20.sol";
// TODO remove this contract and work with an instance of ZRX compiled with 0.4
// when the following is resolved https://linear.app/0xproject/issue/PRO-44/zrx-artifact-is-incompatible-with-foundry
contract ZRXMock is ERC20 {
constructor() ERC20("0x Protocol Token", "ZRX") {
_mint(msg.sender, 10 ** 27);
}
}

View File

@ -1,11 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract ZeroExMock {
mapping(bytes4 => address) public implementations;
function rollback(bytes4 selector, address targetImpl) public {
implementations[selector] = targetImpl;
}
}

View File

@ -1,32 +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.19;
import "../../src/ZeroExVotes.sol";
contract ZeroExVotesMalicious is ZeroExVotes {
constructor(address _token, uint256 _quadraticThreshold) ZeroExVotes(_token, _quadraticThreshold) {}
function writeCheckpointTotalSupplyBurn(
uint256 amount,
uint256 accountBalance
) public virtual override onlyToken returns (bool) {
revert("I am evil");
}
}

View File

@ -1,215 +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.19;
import {ZeroExVotes} from "../../src/ZeroExVotes.sol";
import {SafeCast} from "@openzeppelin/utils/math/SafeCast.sol";
import {Math} from "@openzeppelin/utils/math/Math.sol";
import {CubeRoot} from "./CubeRoot.sol";
contract ZeroExVotesMigration is ZeroExVotes {
uint32 public migrationBlock;
constructor(address _token, uint256 _quadraticThreshold) ZeroExVotes(_token, _quadraticThreshold) {}
function initialize() public virtual override onlyProxy reinitializer(2) {
migrationBlock = uint32(block.number);
}
struct CheckpointMigration {
uint32 fromBlock;
uint96 votes;
uint96 quadraticVotes;
uint32 migratedVotes;
}
function _toMigration(Checkpoint storage ckpt) internal pure returns (CheckpointMigration storage result) {
assembly {
result.slot := ckpt.slot
}
}
function _toMigration(Checkpoint[] storage ckpt) internal pure returns (CheckpointMigration[] storage result) {
assembly {
result.slot := ckpt.slot
}
}
function getMigratedVotes(address account) public view returns (uint256) {
uint256 pos = _checkpoints[account].length;
if (pos == 0) {
return 0;
}
Checkpoint storage ckpt = _unsafeAccess(_checkpoints[account], pos - 1);
if (ckpt.fromBlock <= migrationBlock) {
return 0;
}
return _toMigration(ckpt).migratedVotes;
}
function getPastMigratedVotes(address account, uint256 blockNumber) public view returns (uint256) {
require(blockNumber < block.number, "ZeroExVotesMigration: block not yet mined");
if (blockNumber <= migrationBlock) {
return 0;
}
Checkpoint storage checkpoint = _checkpointsLookupStorage(_checkpoints[account], blockNumber);
if (checkpoint.fromBlock <= migrationBlock) {
return 0;
}
return _toMigration(checkpoint).migratedVotes;
}
function _checkpointsLookupStorage(
Checkpoint[] storage ckpts,
uint256 blockNumber
) internal view returns (Checkpoint storage result) {
// We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
//
// Initially we check if the block is recent to narrow the search range.
// During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
// With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the
// invariant.
// - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
// - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
// Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
// out of bounds (in which case we're looking too far in the past and the result is 0).
// Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
// past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
// the same.
uint256 length = ckpts.length;
uint256 low = 0;
uint256 high = length;
if (length > 5) {
uint256 mid = length - Math.sqrt(length);
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
high = mid;
} else {
low = mid + 1;
}
}
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
high = mid;
} else {
low = mid + 1;
}
}
// Leaving here for posterity this is the original OZ implementation which we've replaced
// return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
// Checkpoint memory checkpoint = high == 0 ? Checkpoint(0, 0, 0) : _unsafeAccess(ckpts, high - 1);
// return checkpoint;
// TODO: bad. very bad. only works on accident
if (high > 0) {
result = _unsafeAccess(ckpts, high - 1);
} else {
// suppress compiler warning, which really shouldn't be suppressed
assembly {
result.slot := 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
}
}
}
// TODO: we're not handling totalSupply
// TODO: need to return the migrated weight
function _writeCheckpoint(
Checkpoint[] storage ckpts,
function(uint256, uint256) view returns (uint256) op,
uint256 userBalance,
uint96 balanceLastUpdated,
uint256 delta
)
internal
virtual
override
returns (uint256 oldWeight, uint256 newWeight, uint256 oldQuadraticWeight, uint256 newQuadraticWeight)
{
uint256 pos = ckpts.length;
CheckpointMigration memory oldCkpt = pos == 0
? CheckpointMigration(0, 0, 0, 0)
: _toMigration(_unsafeAccess(ckpts, pos - 1));
oldWeight = oldCkpt.votes;
newWeight = op(oldWeight, delta);
oldQuadraticWeight = oldCkpt.quadraticVotes;
if (pos > 0) {
deductOldWeightFromCheckpoint(oldCkpt, userBalance, balanceLastUpdated);
}
// if wallet > threshold, calculate quadratic power over the treshold only, below threshold is linear
uint256 newBalance = op(userBalance, delta);
uint256 newQuadraticBalance = newBalance <= quadraticThreshold
? newBalance
: quadraticThreshold + Math.sqrt((newBalance - quadraticThreshold) * 1e18);
newQuadraticWeight = oldCkpt.quadraticVotes + newQuadraticBalance;
uint256 newMigratedWeight = oldCkpt.migratedVotes + CubeRoot.cbrt(newBalance);
if (pos > 0 && oldCkpt.fromBlock == block.number) {
addCheckpoint(ckpts, pos, newWeight, newQuadraticWeight, newMigratedWeight);
} else {
_toMigration(ckpts).push(
CheckpointMigration({
fromBlock: SafeCast.toUint32(block.number),
votes: SafeCast.toUint96(newWeight),
quadraticVotes: SafeCast.toUint96(newQuadraticWeight),
migratedVotes: SafeCast.toUint32(newMigratedWeight)
})
);
}
}
function deductOldWeightFromCheckpoint(
CheckpointMigration memory oldCkpt,
uint256 userBalance,
uint96 balanceLastUpdated
) internal {
// Remove the entire sqrt userBalance from quadratic voting power.
// Note that `userBalance` is value _after_ transfer.
uint256 oldQuadraticVotingPower = userBalance <= quadraticThreshold
? userBalance
: quadraticThreshold + Math.sqrt((userBalance - quadraticThreshold) * 1e18);
oldCkpt.quadraticVotes -= SafeCast.toUint96(oldQuadraticVotingPower);
if (balanceLastUpdated > migrationBlock) {
oldCkpt.migratedVotes -= SafeCast.toUint32(CubeRoot.cbrt(userBalance));
}
}
function addCheckpoint(
Checkpoint[] storage ckpts,
uint256 pos,
uint256 newWeight,
uint256 newQuadraticWeight,
uint256 newMigratedWeight
) internal {
CheckpointMigration storage chpt = _toMigration(_unsafeAccess(ckpts, pos - 1));
chpt.votes = SafeCast.toUint96(newWeight);
chpt.quadraticVotes = SafeCast.toUint96(newQuadraticWeight);
chpt.migratedVotes = SafeCast.toUint32(newMigratedWeight);
}
}

View File

@ -1,315 +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.19;
import "../BaseTest.t.sol";
import "../../src/ZRXWrappedToken.sol";
import "@openzeppelin/token/ERC20/ERC20.sol";
contract ZRXWrappedTokenTest is BaseTest {
IERC20 private token;
ZRXWrappedToken private wToken;
ZeroExVotes private votes;
function setUp() public {
token = mockZRXToken();
(wToken, votes, , , , ) = setupGovernance(token);
vm.startPrank(account1);
token.transfer(account2, 100e18);
token.transfer(account3, 200e18);
vm.stopPrank();
}
function testShouldReturnCorrectSymbol() public {
string memory wZRXSymbol = wToken.symbol();
assertEq(wZRXSymbol, "wZRX");
}
function testShouldReturnCorrectName() public {
string memory wZRXName = wToken.name();
assertEq(wZRXName, "Wrapped ZRX");
}
function testShouldReturnCorrectNumberOfDecimals() public {
uint8 wZRXDecimals = wToken.decimals();
assertEq(wZRXDecimals, 18);
}
function testShouldBeAbleToWrapZRX() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
// Check the token balances even out
uint256 wTokenBalance = wToken.balanceOf(account2);
assertEq(wTokenBalance, 1e18);
uint256 tokenBalance = token.balanceOf(account2);
assertEq(tokenBalance, 100e18 - wTokenBalance);
}
function testShouldBeAbleToUnwrapToZRX() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
// Withdraw 1e6 wZRX back to ZRX to own account
wToken.withdrawTo(account2, 1e6);
// Check token balances even out
uint256 wTokenBalance = wToken.balanceOf(account2);
assertEq(wTokenBalance, 1e18 - 1e6);
uint256 tokenBalance = token.balanceOf(account2);
assertEq(tokenBalance, 100e18 - wTokenBalance);
}
function testShouldBeAbleToUnwrapToZRXToAnotherAccount() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
// Withdraw 1e7 wZRX back to ZRX to account4 (which owns no tokens to start with)
wToken.withdrawTo(account4, 1e7);
// Check token balances even out
uint256 wTokenBalance2 = wToken.balanceOf(account2);
assertEq(wTokenBalance2, 1e18 - 1e7);
uint256 tokenBalance4 = token.balanceOf(account4);
assertEq(tokenBalance4, 1e7);
uint256 tokenBalance2 = token.balanceOf(account2);
assertEq(tokenBalance2, 100e18 - wTokenBalance2 - tokenBalance4);
}
function testWrappedZRXTotalsAreCorrect() public {
// Wrap 1e18 and check total supply is correct
vm.startPrank(account2);
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
vm.stopPrank();
uint256 wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 1e18);
// Wrap 2e18 more and check total supply is correct
vm.startPrank(account3);
token.approve(address(wToken), 2e18);
wToken.depositFor(account3, 2e18);
vm.stopPrank();
wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 1e18 + 2e18);
// Unwrap 1e7 and check total supply is correct
vm.startPrank(account2);
wToken.withdrawTo(account2, 1e7);
vm.stopPrank();
wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 3e18 - 1e7);
// Unwrap 8e17 and check total supply is correct
vm.startPrank(account2);
wToken.withdrawTo(account2, 8e17);
vm.stopPrank();
wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 3e18 - 1e7 - 8e17);
// We are not keeping record of total balances so check they are zero
assertEq(votes.getPastTotalSupply(0), 0);
assertEq(votes.getPastQuadraticTotalSupply(0), 0);
}
function testWhenMintingFirstTimeForAccountTotalSupplyCheckpointsAreCorrect() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
vm.roll(2);
wToken.depositFor(account2, 1e18);
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 1e18);
assertEq(totalSupplyQuadraticVotes, 1e18);
}
function testWhenMintingForAccountWithExistingBalanceTotalSupplyCheckpointsAreCorrect() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 5e18);
wToken.depositFor(account2, 1e18);
vm.roll(2);
// Depost 3e18 more for the same account
wToken.depositFor(account2, 3e18);
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 4e18);
assertEq(totalSupplyQuadraticVotes, 4e18);
}
function testWhenMintingForMultipleAccountsTotalSupplyCheckpointsAreCorrect() public {
// Deposit 1e18 ZRX by account2
vm.startPrank(account2);
token.approve(address(wToken), 5e18);
wToken.depositFor(account2, 1e18);
vm.stopPrank();
// Deposit 2e18 ZRX by account3
vm.startPrank(account3);
token.approve(address(wToken), 2e18);
wToken.depositFor(account3, 2e18);
vm.stopPrank();
// Deposit 4e18 ZRX by account2
vm.startPrank(account2);
vm.roll(2);
wToken.depositFor(account2, 4e18);
vm.stopPrank();
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 7e18);
assertEq(totalSupplyQuadraticVotes, 5e18 + 2e18);
}
function testWhenBurningForMultipleAccountsTotalSupplyCheckpointsAreCorrect() public {
// Deposit 5e18 ZRX by account2
vm.startPrank(account2);
token.approve(address(wToken), 5e18);
wToken.depositFor(account2, 5e18);
vm.stopPrank();
// Deposit 2e18 ZRX by account3
vm.startPrank(account3);
token.approve(address(wToken), 2e18);
wToken.depositFor(account3, 2e18);
vm.stopPrank();
// Burn 4e18 ZRX by account2
vm.startPrank(account2);
vm.roll(2);
wToken.withdrawTo(account2, 4e18);
vm.stopPrank();
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 3e18);
assertEq(totalSupplyQuadraticVotes, 1e18 + 2e18);
}
function testShouldBeAbleToTransferCorrectly() public {
assertEq(wToken.balanceOf(account4), 0);
vm.startPrank(account2);
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
wToken.transfer(account4, 1e17);
vm.stopPrank();
assertEq(wToken.balanceOf(account4), 1e17);
}
function testShouldTransferVotingPowerWhenTransferringTokens() public {
// Account 2 wraps ZRX and delegates voting power to itself
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 10e18);
wToken.delegate(account2);
wToken.transfer(account3, 3e18);
assertEq(wToken.balanceOf(account2), 7e18);
assertEq(wToken.balanceOf(account3), 3e18);
assertEq(votes.getVotes(account2), 7e18);
assertEq(votes.getQuadraticVotes(account2), 7e18);
// Since account3 is not delegating to anyone, they should have no voting power
assertEq(votes.getVotes(account3), 0);
assertEq(votes.getQuadraticVotes(account3), 0);
}
function testShouldUpdateVotingPowerWhenDepositing() public {
// Account 2 wraps ZRX and delegates voting power to itself
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 7e18);
wToken.delegate(account2);
assertEq(votes.getVotes(account2), 7e18);
assertEq(votes.getQuadraticVotes(account2), 7e18);
wToken.depositFor(account2, 2e18);
assertEq(votes.getVotes(account2), 9e18);
assertEq(votes.getQuadraticVotes(account2), 9e18);
}
function testShouldUpdateVotingPowerWhenWithdrawing() public {
// Account 2 wraps ZRX and delegates voting power to itself
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 10e18);
wToken.delegate(account2);
assertEq(votes.getVotes(account2), 10e18);
assertEq(votes.getQuadraticVotes(account2), 10e18);
wToken.withdrawTo(account2, 2e18);
assertEq(votes.getVotes(account2), 8e18);
assertEq(votes.getQuadraticVotes(account2), 8e18);
}
function testShouldSetDelegateBalanceLastUpdatedOnTransfer() public {
ZRXWrappedToken.DelegateInfo memory account2DelegateInfo = wToken.delegateInfo(account2);
assertEq(account2DelegateInfo.delegate, address(0));
assertEq(account2DelegateInfo.balanceLastUpdated, 0);
// Account 2 wraps ZRX and delegates voting power to account3
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 10e18);
wToken.delegate(account3);
account2DelegateInfo = wToken.delegateInfo(account2);
assertEq(account2DelegateInfo.delegate, account3);
assertEq(account2DelegateInfo.balanceLastUpdated, 1); // Set to the block.number
vm.roll(3);
wToken.transfer(account3, 3e18);
account2DelegateInfo = wToken.delegateInfo(account2);
assertEq(account2DelegateInfo.delegate, account3);
assertEq(account2DelegateInfo.balanceLastUpdated, 3);
}
}

View File

@ -1,453 +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 IZeroExGovernorANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.19;
import "../BaseTest.t.sol";
import "../../src/IZeroExGovernor.sol";
import "../../src/ZeroExTimelock.sol";
import "../../src/ZeroExProtocolGovernor.sol";
import "../../src/ZRXWrappedToken.sol";
import "@openzeppelin/token/ERC20/ERC20.sol";
import "@openzeppelin/mocks/CallReceiverMock.sol";
abstract contract ZeroExGovernorBaseTest is BaseTest {
IERC20 public token;
ZRXWrappedToken internal wToken;
ZeroExVotes internal votes;
ZeroExTimelock internal timelock;
IZeroExGovernor internal governor;
CallReceiverMock internal callReceiverMock;
string internal governorName;
uint256 internal proposalThreshold;
event SecurityCouncilAssigned(address securityCouncil);
event SecurityCouncilEjected();
function initialiseAccounts() public {
vm.startPrank(account1);
token.transfer(account2, 10000000e18);
token.transfer(account3, 2000000e18);
token.transfer(account4, 3000000e18);
vm.stopPrank();
// Setup accounts 2,3 and 4 to vote
vm.startPrank(account2);
token.approve(address(wToken), 10000000e18);
wToken.depositFor(account2, 10000000e18);
wToken.delegate(account2);
vm.stopPrank();
vm.startPrank(account3);
token.approve(address(wToken), 2000000e18);
wToken.depositFor(account3, 2000000e18);
wToken.delegate(account3);
vm.stopPrank();
vm.startPrank(account4);
token.approve(address(wToken), 3000000e18);
wToken.depositFor(account4, 3000000e18);
wToken.delegate(account4);
vm.stopPrank();
callReceiverMock = new CallReceiverMock();
}
function setSecurityCouncil(address council) internal {
address[] memory targets = new address[](1);
targets[0] = address(governor);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(governor.assignSecurityCouncil.selector, council);
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Assign new security council");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Assign new security council")));
vm.warp(governor.proposalEta(proposalId) + 1);
// Execute proposal
governor.execute(targets, values, calldatas, keccak256("Assign new security council"));
assertEq(governor.securityCouncil(), council);
}
function testShouldReturnCorrectName() public {
assertEq(governor.name(), governorName);
}
function testShouldReturnCorrectVotingDelay() public {
assertEq(governor.votingDelay(), 14400);
}
function testShouldReturnCorrectVotingPeriod() public {
assertEq(governor.votingPeriod(), 50400);
}
function testShouldReturnCorrectProposalThreshold() public {
assertEq(governor.proposalThreshold(), proposalThreshold);
}
function testShouldReturnCorrectToken() public {
assertEq(address(governor.token()), address(votes));
}
function testShouldReturnCorrectTimelock() public {
assertEq(address(governor.timelock()), address(timelock));
}
function testShouldReturnCorrectSecurityCouncil() public {
assertEq(governor.securityCouncil(), securityCouncil);
}
function testCanAssignSecurityCouncil() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(governor);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(governor.assignSecurityCouncil.selector, account1);
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Assign new security council");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Assign new security council")));
vm.warp(governor.proposalEta(proposalId) + 1);
// Execute proposal
vm.expectEmit(true, false, false, false);
emit SecurityCouncilAssigned(account1);
governor.execute(targets, values, calldatas, keccak256("Assign new security council"));
assertEq(governor.securityCouncil(), account1);
}
function testCannotAssignSecurityCouncilOutsideOfGovernance() public {
vm.expectRevert("Governor: onlyGovernance");
governor.assignSecurityCouncil(account1);
}
// This functionality is currently not enabled
// Leaving this test for potential future use.
function testFailSecurityCouncilAreEjectedAfterCancellingAProposal() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(callReceiverMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("mockFunction()");
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
vm.stopPrank();
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
IGovernor.ProposalState state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
// Cancel the proposal
vm.warp(governor.proposalEta(proposalId));
vm.prank(securityCouncil);
vm.expectEmit(true, false, false, false);
emit SecurityCouncilEjected();
governor.cancel(targets, values, calldatas, keccak256(bytes("Proposal description")));
vm.stopPrank();
state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Canceled));
assertEq(governor.securityCouncil(), address(0));
}
function testWhenNoSecurityCouncilCannottSubmitProposals() public {
setSecurityCouncil(address(0));
address[] memory targets = new address[](1);
targets[0] = address(callReceiverMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("mockFunction()");
vm.expectRevert("SecurityCouncil: security council not assigned and this is not an assignment call");
governor.propose(targets, values, calldatas, "Proposal description");
}
function testWhenNoSecurityCouncilCannotQueueSuccessfulProposals() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(callReceiverMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("mockFunction()");
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Set security council to address(0)
setSecurityCouncil(address(0));
vm.expectRevert("SecurityCouncil: security council not assigned and this is not an assignment call");
governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
IGovernor.ProposalState state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
}
function testWhenNoSecurityCouncilCanPassProposalToAssignSecurityCouncil() public {
setSecurityCouncil(address(0));
setSecurityCouncil(account1);
}
function testCannotPassABadProposalToSetSecurityCouncil() public {
setSecurityCouncil(address(0));
address[] memory targets = new address[](2);
targets[0] = address(governor);
targets[1] = address(callReceiverMock);
uint256[] memory values = new uint256[](2);
values[0] = 0;
values[1] = 0;
bytes[] memory calldatas = new bytes[](2);
calldatas[0] = abi.encodeWithSelector(governor.assignSecurityCouncil.selector, account1);
calldatas[1] = abi.encodeWithSignature("mockFunction()");
vm.roll(2);
vm.startPrank(account2);
vm.expectRevert("SecurityCouncil: more than 1 transaction in proposal");
governor.propose(targets, values, calldatas, "Assign new security council");
}
function testCanUpdateVotingDelaySetting() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(governor);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(governor.setVotingDelay.selector, 3 days);
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Increase voting delay to 3 days");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Increase voting delay to 3 days")));
vm.warp(governor.proposalEta(proposalId) + 1);
// Execute proposal
governor.execute(targets, values, calldatas, keccak256("Increase voting delay to 3 days"));
assertEq(governor.votingDelay(), 3 days);
}
function testCanUpdateVotingPeriodSetting() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(governor);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(governor.setVotingPeriod.selector, 14 days);
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Increase voting period to 14 days");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Increase voting period to 14 days")));
vm.warp(governor.proposalEta(proposalId) + 1);
// Execute proposal
governor.execute(targets, values, calldatas, keccak256("Increase voting period to 14 days"));
assertEq(governor.votingPeriod(), 14 days);
}
function testCanUpdateProposalThresholdSetting() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(governor);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(governor.setProposalThreshold.selector, 2000000e18);
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Increase proposal threshold to 2000000e18");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Increase proposal threshold to 2000000e18")));
vm.warp(governor.proposalEta(proposalId) + 1);
// Execute proposal
governor.execute(targets, values, calldatas, keccak256("Increase proposal threshold to 2000000e18"));
assertEq(governor.proposalThreshold(), 2000000e18);
}
function testCanUpdateTimelockDelay() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(timelock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSelector(timelock.updateDelay.selector, 7 days);
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Increase timelock delay to 7 days");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Increase timelock delay to 7 days")));
vm.warp(governor.proposalEta(proposalId) + 1);
// Execute proposal
governor.execute(targets, values, calldatas, keccak256("Increase timelock delay to 7 days"));
assertEq(timelock.getMinDelay(), 7 days);
}
function testSupportsGovernanceInterfaces() public {
assertTrue(governor.supportsInterface(type(IGovernorTimelock).interfaceId));
assertTrue(governor.supportsInterface(type(IGovernor).interfaceId));
assertTrue(governor.supportsInterface(type(IERC1155Receiver).interfaceId));
}
}

View File

@ -1,168 +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.19;
import "./ZeroExGovernorBaseTest.t.sol";
import "../mocks/ZeroExMock.sol";
import "../../src/ZeroExProtocolGovernor.sol";
contract ZeroExProtocolGovernorTest is ZeroExGovernorBaseTest {
ZeroExProtocolGovernor internal protocolGovernor;
ZeroExMock internal zeroExMock;
uint256 internal quorum;
event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);
function setUp() public {
governorName = "ZeroExProtocolGovernor";
proposalThreshold = 1000000e18;
quorum = 10000000e18;
address governorAddress;
token = mockZRXToken();
(wToken, votes, timelock, , governorAddress, ) = setupGovernance(token);
governor = IZeroExGovernor(governorAddress);
protocolGovernor = ZeroExProtocolGovernor(payable(governorAddress));
zeroExMock = new ZeroExMock();
initialiseAccounts();
}
function testShouldReturnCorrectQuorum() public {
assertEq(governor.quorum(block.number), quorum);
}
function testShouldBeAbleToExecuteASuccessfulProposal() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(callReceiverMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("mockFunction()");
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
vm.prank(account3);
governor.castVote(proposalId, 0); // Vote "against"
vm.prank(account4);
governor.castVote(proposalId, 2); // Vote "abstain"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Get vote results
(uint256 votesAgainst, uint256 votesFor, uint256 votesAbstain) = governor.proposalVotes(proposalId);
assertEq(votesFor, 10000000e18);
assertEq(votesAgainst, 2000000e18);
assertEq(votesAbstain, 3000000e18);
IGovernor.ProposalState state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
vm.warp(governor.proposalEta(proposalId) + 1);
governor.execute(targets, values, calldatas, keccak256("Proposal description"));
state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Executed));
}
function testSecurityCouncilShouldBeAbleToExecuteRollback() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(zeroExMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
bytes4 testFunctionSig = 0xc853c969;
address testFunctionImpl = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
calldatas[0] = abi.encodeWithSignature("rollback(bytes4,address)", testFunctionSig, testFunctionImpl);
// Security council adds the batch of rollbacks to the queue
vm.startPrank(securityCouncil);
bytes32 proposalId = timelock.hashOperationBatch(
targets,
values,
calldatas,
0,
keccak256(bytes("Emergency rollback"))
);
vm.expectEmit(true, true, true, true);
emit CallExecuted(proposalId, 0, targets[0], values[0], calldatas[0]);
// This functionality is currently not enabled
// Leaving this test for potential future use.
// vm.expectEmit(true, false, false, false);
// emit SecurityCouncilEjected();
protocolGovernor.executeRollback(targets, values, calldatas, keccak256(bytes("Emergency rollback")));
}
function testSecurityCouncilShouldNotBeAbleToExecuteArbitraryFunctions() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(callReceiverMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("mockFunction()");
vm.startPrank(securityCouncil);
vm.expectRevert("ZeroExTimelock: not rollback");
protocolGovernor.executeRollback(targets, values, calldatas, keccak256(bytes("Proposal description")));
}
function testRollbackShouldNotBeExecutableByNonSecurityCouncilAccounts() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(zeroExMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
bytes4 testFunctionSig = 0xc853c969;
address testFunctionImpl = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
calldatas[0] = abi.encodeWithSignature("rollback(bytes4,address)", testFunctionSig, testFunctionImpl);
vm.startPrank(account2);
vm.expectRevert("SecurityCouncil: only security council allowed");
protocolGovernor.executeRollback(targets, values, calldatas, keccak256(bytes("Emergency rollback")));
}
}

View File

@ -1,96 +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.19;
import "./ZeroExGovernorBaseTest.t.sol";
contract ZeroExTreasuryGovernorTest is ZeroExGovernorBaseTest {
function setUp() public {
governorName = "ZeroExTreasuryGovernor";
proposalThreshold = 250000e18;
address governorAddress;
token = mockZRXToken();
(wToken, votes, , timelock, , governorAddress) = setupGovernance(token);
governor = IZeroExGovernor(governorAddress);
initialiseAccounts();
}
function testShouldReturnCorrectQuorum() public {
vm.roll(3);
uint256 totalSupplyQuadraticVotes = quadraticThreshold *
3 +
Math.sqrt((10000000e18 - quadraticThreshold) * 1e18) +
Math.sqrt((2000000e18 - quadraticThreshold) * 1e18) +
Math.sqrt((3000000e18 - quadraticThreshold) * 1e18);
uint256 quorum = (totalSupplyQuadraticVotes * 10) / 100;
assertEq(governor.quorum(2), quorum);
}
function testShouldBeAbleToExecuteASuccessfulProposal() public {
// Create a proposal
address[] memory targets = new address[](1);
targets[0] = address(callReceiverMock);
uint256[] memory values = new uint256[](1);
values[0] = 0;
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = abi.encodeWithSignature("mockFunction()");
vm.roll(2);
vm.startPrank(account2);
uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
vm.stopPrank();
// Fast forward to after vote start
vm.roll(governor.proposalSnapshot(proposalId) + 1);
// Vote
vm.prank(account2);
governor.castVote(proposalId, 1); // Vote "for"
vm.prank(account3);
governor.castVote(proposalId, 0); // Vote "against"
vm.prank(account4);
governor.castVote(proposalId, 2); // Vote "abstain"
// Fast forward to vote end
vm.roll(governor.proposalDeadline(proposalId) + 1);
// Get vote results
(uint256 votesAgainst, uint256 votesFor, uint256 votesAbstain) = governor.proposalVotes(proposalId);
assertEq(votesFor, (quadraticThreshold + Math.sqrt((10000000e18 - quadraticThreshold) * 1e18)));
assertEq(votesAgainst, quadraticThreshold + Math.sqrt((2000000e18 - quadraticThreshold) * 1e18));
assertEq(votesAbstain, quadraticThreshold + Math.sqrt((3000000e18 - quadraticThreshold) * 1e18));
IGovernor.ProposalState state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
// Queue proposal
governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
vm.warp(governor.proposalEta(proposalId) + 1);
governor.execute(targets, values, calldatas, keccak256("Proposal description"));
state = governor.state(proposalId);
assertEq(uint256(state), uint256(IGovernor.ProposalState.Executed));
}
}

View File

@ -1,435 +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.19;
import "@openzeppelin/token/ERC20/ERC20.sol";
import "../BaseTest.t.sol";
import "../mocks/ZeroExVotesMalicious.sol";
import "../mocks/ZeroExVotesMigration.sol";
import "../../src/ZRXWrappedToken.sol";
import "../../src/ZeroExVotes.sol";
contract ZeroExVotesTest is BaseTest {
IERC20 internal token;
ZRXWrappedToken internal wToken;
ZeroExVotes internal votes;
function setUp() public {
token = mockZRXToken();
(wToken, votes) = setupZRXWrappedToken(token);
vm.startPrank(account1);
token.transfer(account2, 1700000e18);
token.transfer(account3, 1600000e18);
token.transfer(account4, 1000000e18);
vm.stopPrank();
}
function testShouldCorrectlyInitialiseToken() public {
assertEq(votes.token(), address(wToken));
}
function testShouldNotBeAbleToReinitialise() public {
vm.expectRevert("Initializable: contract is already initialized");
votes.initialize();
}
function testShouldBeAbleToMigrate() public {
vm.roll(block.number + 1);
vm.startPrank(account2);
token.approve(address(wToken), 100e18);
wToken.depositFor(account2, 100e18);
wToken.delegate(account3);
vm.stopPrank();
vm.startPrank(account3);
token.approve(address(wToken), 200e18);
wToken.depositFor(account3, 200e18);
wToken.delegate(account3);
vm.stopPrank();
assertEq(votes.getVotes(account3), 300e18);
assertEq(votes.getQuadraticVotes(account3), 300e18);
vm.roll(block.number + 1);
ZeroExVotesMigration newImpl = new ZeroExVotesMigration(address(wToken), quadraticThreshold);
assertFalse(
address(
uint160(
uint256(vm.load(address(votes), 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc))
)
) == address(newImpl)
);
vm.prank(account1);
votes.upgradeToAndCall(address(newImpl), abi.encodeWithSignature("initialize()"));
assertEq(
address(
uint160(
uint256(vm.load(address(votes), 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc))
)
),
address(newImpl)
);
ZeroExVotesMigration upgradedVotes = ZeroExVotesMigration(address(votes));
assertEq(upgradedVotes.getVotes(account3), 300e18);
assertEq(upgradedVotes.getQuadraticVotes(account3), 300e18);
vm.roll(block.number + 1);
vm.prank(account2);
wToken.transfer(address(this), 50e18);
assertEq(upgradedVotes.getVotes(account3), 250e18);
assertEq(upgradedVotes.getQuadraticVotes(account3), 250e18);
assertEq(upgradedVotes.getMigratedVotes(account3), CubeRoot.cbrt(50e18));
vm.prank(account3);
wToken.transfer(address(this), 100e18);
assertEq(upgradedVotes.getVotes(account3), 150e18);
assertEq(upgradedVotes.getQuadraticVotes(account3), 150e18);
assertEq(upgradedVotes.getMigratedVotes(account3), CubeRoot.cbrt(50e18) + CubeRoot.cbrt(100e18));
}
function testShouldNotBeAbleToStopBurn() public {
// wrap some token
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
vm.stopPrank();
assertEq(token.balanceOf(account2), 0);
assertEq(wToken.balanceOf(account2), 1700000e18);
// malicious upgrade
vm.startPrank(account1);
IZeroExVotes maliciousImpl = new ZeroExVotesMalicious(votes.token(), votes.quadraticThreshold());
votes.upgradeTo(address(maliciousImpl));
vm.stopPrank();
// try to withdraw withdraw
vm.prank(account2);
wToken.withdrawTo(account2, 1700000e18);
assertEq(token.balanceOf(account2), 1700000e18);
assertEq(wToken.balanceOf(account2), 0);
}
function testShouldBeAbleToReadCheckpoints() public {
// Account 2 wraps ZRX and delegates voting power to account3
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
vm.roll(2);
wToken.delegate(account3);
assertEq(votes.numCheckpoints(account3), 1);
IZeroExVotes.Checkpoint memory checkpoint = votes.checkpoints(account3, 0);
assertEq(checkpoint.fromBlock, 2);
assertEq(checkpoint.votes, 1700000e18);
assertEq(checkpoint.quadraticVotes, quadraticThreshold + Math.sqrt((1700000e18 - quadraticThreshold) * 1e18));
}
function testShouldBeAbleToSelfDelegateVotingPower() public {
// Check voting power initially is 0
assertEq(votes.getVotes(account2), 0);
assertEq(votes.getQuadraticVotes(account2), 0);
// Wrap ZRX and delegate voting power to themselves
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
wToken.delegate(account2);
// Check voting power
assertEq(votes.getVotes(account2), 1700000e18);
assertEq(
votes.getQuadraticVotes(account2),
quadraticThreshold + Math.sqrt((1700000e18 - quadraticThreshold) * 1e18)
);
}
function testShouldBeAbleToDelegateVotingPowerToAnotherAccount() public {
// Check voting power initially is 0
assertEq(votes.getVotes(account3), 0);
assertEq(votes.getQuadraticVotes(account3), 0);
// Account 2 wraps ZRX and delegates voting power to account3
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
wToken.delegate(account3);
// Check voting power
assertEq(votes.getVotes(account3), 1700000e18);
assertEq(
votes.getQuadraticVotes(account3),
quadraticThreshold + Math.sqrt((1700000e18 - quadraticThreshold) * 1e18)
);
}
function testShouldBeAbleToDelegateVotingPowerToAnotherAccountWithSignature() public {
uint256 nonce = 0;
uint256 expiry = type(uint256).max;
uint256 privateKey = 2;
// Account 2 wraps ZRX and delegates voting power to account3
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
vm.stopPrank();
assertEq(wToken.delegates(account2), address(0));
assertEq(votes.getVotes(account3), 0);
assertEq(votes.getQuadraticVotes(account3), 0);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
privateKey,
keccak256(
abi.encodePacked(
"\x19\x01",
wToken.DOMAIN_SEPARATOR(),
keccak256(abi.encode(DELEGATION_TYPEHASH, account3, nonce, expiry))
)
)
);
wToken.delegateBySig(account3, nonce, expiry, v, r, s);
assertEq(wToken.delegates(account2), account3);
assertEq(votes.getVotes(account3), 1700000e18);
assertEq(
votes.getQuadraticVotes(account3),
quadraticThreshold + Math.sqrt((1700000e18 - quadraticThreshold) * 1e18)
);
}
function testShouldNotBeAbleToDelegateWithSignatureAfterExpiry() public {
uint256 nonce = 0;
uint256 expiry = block.timestamp - 1;
uint256 privateKey = 2;
// Account 2 wraps ZRX and delegates voting power to account3
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
vm.stopPrank();
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
privateKey,
keccak256(
abi.encodePacked(
"\x19\x01",
wToken.DOMAIN_SEPARATOR(),
keccak256(abi.encode(DELEGATION_TYPEHASH, account3, nonce, expiry))
)
)
);
vm.expectRevert("ERC20Votes: signature expired");
wToken.delegateBySig(account3, nonce, expiry, v, r, s);
}
function testMultipleAccountsShouldBeAbleToDelegateVotingPowerToAccountWithNoTokensOnSameBlock() public {
// Check account4 voting power initially is 0
assertEq(votes.getVotes(account4), 0);
assertEq(votes.getQuadraticVotes(account4), 0);
// Account 2 wraps ZRX and delegates voting power to account4
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
wToken.delegate(account4);
vm.stopPrank();
// Account 3 also wraps ZRX and delegates voting power to account4
vm.startPrank(account3);
token.approve(address(wToken), 1600000e18);
wToken.depositFor(account3, 1600000e18);
wToken.delegate(account4);
vm.stopPrank();
// Check voting power
assertEq(votes.getVotes(account4), 3300000e18);
assertEq(
votes.getQuadraticVotes(account4),
quadraticThreshold *
2 +
Math.sqrt((1700000e18 - quadraticThreshold) * 1e18) +
Math.sqrt((1600000e18 - quadraticThreshold) * 1e18)
);
}
function testMultipleAccountsShouldBeAbleToDelegateVotingPowerToAccountWithNoTokensOnDifferentBlock() public {
// Check account4 voting power initially is 0
assertEq(votes.getVotes(account4), 0);
assertEq(votes.getQuadraticVotes(account4), 0);
// Account 2 wraps ZRX and delegates voting power to account4
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1700000e18);
wToken.delegate(account4);
vm.stopPrank();
// Different block height
vm.roll(2);
// Account 3 also wraps ZRX and delegates voting power to account4
vm.startPrank(account3);
token.approve(address(wToken), 1600000e18);
wToken.depositFor(account3, 1600000e18);
wToken.delegate(account4);
vm.stopPrank();
// Check voting power
assertEq(votes.getVotes(account4), 3300000e18);
assertEq(
votes.getQuadraticVotes(account4),
quadraticThreshold *
2 +
Math.sqrt((1700000e18 - quadraticThreshold) * 1e18) +
Math.sqrt((1600000e18 - quadraticThreshold) * 1e18)
);
}
function testComplexDelegationScenario() public {
// Account 2 wraps ZRX and delegates to itself
vm.startPrank(account2);
token.approve(address(wToken), 1700000e18);
wToken.depositFor(account2, 1000000e18);
wToken.delegate(account2);
vm.stopPrank();
assertEq(votes.getVotes(account2), 1000000e18);
assertEq(votes.getQuadraticVotes(account2), 1000000e18);
// Account 3 wraps ZRX and delegates to account4
vm.startPrank(account3);
token.approve(address(wToken), 500000e18);
wToken.depositFor(account3, 500000e18);
wToken.delegate(account4);
vm.stopPrank();
assertEq(votes.getVotes(account4), 500000e18);
assertEq(votes.getQuadraticVotes(account4), 500000e18);
// Voting power distribution now is as follows
// account2 -> account2 1000000e18 | 1000000e18
// account3 -> account4 500000e18 | 500000e18
// Account 2 deposits the remaining 700000e18 and delegates to account3
vm.startPrank(account2);
wToken.depositFor(account2, 700000e18);
wToken.delegate(account3);
vm.stopPrank();
assertEq(votes.getVotes(account3), 1700000e18);
assertEq(
votes.getQuadraticVotes(account3),
quadraticThreshold + Math.sqrt((1700000e18 - quadraticThreshold) * 1e18)
);
// Voting power distribution now is as follows
// account2 -> account3 1700000e18 | 1000000e18 + Math.sqrt((1700000e18 - 1000000e18) * 1e18)
// account3 -> account4 500000e18 | 500000e18
// Account 3 delegates to itself
vm.startPrank(account3);
wToken.delegate(account3);
vm.stopPrank();
assertEq(votes.getVotes(account3), 2200000e18);
assertEq(
votes.getQuadraticVotes(account3),
quadraticThreshold + Math.sqrt((1700000e18 - quadraticThreshold) * 1e18) + 500000e18
);
// Voting power distribution now is as follows
// account2, account3 -> account3 2200000e18 | 1000000e18 + Math.sqrt((2200000e18-1000000e18) *1e18) + 500000e18
// Check account2 and account4 no longer have voting power
assertEq(votes.getVotes(account2), 0);
assertEq(votes.getQuadraticVotes(account2), 0);
assertEq(votes.getVotes(account4), 0);
assertEq(votes.getQuadraticVotes(account4), 0);
}
function testCheckpointIsCorrectlyUpdatedOnTheSameBlock() public {
// Account 2 wraps ZRX and delegates 20e18 to itself
vm.startPrank(account2);
token.approve(address(wToken), 20e18);
wToken.depositFor(account2, 20e18);
wToken.delegate(account2);
vm.stopPrank();
assertEq(votes.numCheckpoints(account2), 1);
IZeroExVotes.Checkpoint memory checkpoint1Account2 = votes.checkpoints(account2, 0);
assertEq(checkpoint1Account2.fromBlock, 1);
assertEq(checkpoint1Account2.votes, 20e18);
assertEq(checkpoint1Account2.quadraticVotes, 20e18);
// Account 3 wraps ZRX and delegates 10e18 to account2
vm.startPrank(account3);
token.approve(address(wToken), 10e18);
wToken.depositFor(account3, 10e18);
wToken.delegate(account2);
vm.stopPrank();
assertEq(votes.numCheckpoints(account2), 1);
checkpoint1Account2 = votes.checkpoints(account2, 0);
assertEq(checkpoint1Account2.fromBlock, 1);
assertEq(checkpoint1Account2.votes, 30e18);
assertEq(checkpoint1Account2.quadraticVotes, 20e18 + 10e18);
}
function testCheckpointIsCorrectlyUpdatedOnDifferentBlocks() public {
// Account 2 wraps ZRX and delegates 20e18 to itself
vm.startPrank(account2);
token.approve(address(wToken), 20e18);
wToken.depositFor(account2, 20e18);
wToken.delegate(account2);
vm.stopPrank();
assertEq(votes.numCheckpoints(account2), 1);
IZeroExVotes.Checkpoint memory checkpoint1Account2 = votes.checkpoints(account2, 0);
assertEq(checkpoint1Account2.fromBlock, 1);
assertEq(checkpoint1Account2.votes, 20e18);
assertEq(checkpoint1Account2.quadraticVotes, 20e18);
vm.roll(2);
// Account 3 wraps ZRX and delegates 10e18 to account2
vm.startPrank(account3);
token.approve(address(wToken), 10e18);
wToken.depositFor(account3, 10e18);
wToken.delegate(account2);
vm.stopPrank();
assertEq(votes.numCheckpoints(account2), 2);
IZeroExVotes.Checkpoint memory checkpoint2Account2 = votes.checkpoints(account2, 1);
assertEq(checkpoint2Account2.fromBlock, 2);
assertEq(checkpoint2Account2.votes, 30e18);
assertEq(checkpoint2Account2.quadraticVotes, 20e18 + 10e18);
// Check the old checkpoint hasn't changed
checkpoint1Account2 = votes.checkpoints(account2, 0);
assertEq(checkpoint1Account2.fromBlock, 1);
assertEq(checkpoint1Account2.votes, 20e18);
assertEq(checkpoint1Account2.quadraticVotes, 20e18);
}
}

View File

@ -1,121 +1,4 @@
[
{
"timestamp": 1700094997,
"version": "5.4.60",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1693346928,
"version": "5.4.59",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1692368658,
"version": "5.4.58",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1691617396,
"version": "5.4.57",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689974915,
"version": "5.4.56",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689791426,
"version": "5.4.55",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1683749017,
"version": "5.4.54",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1682976338,
"version": "5.4.53",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681969282,
"version": "5.4.52",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681697326,
"version": "5.4.51",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "5.4.50",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1681157139
},
{
"timestamp": 1678410794,
"version": "5.4.49",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1677693479,
"version": "5.4.48",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1675210931,
"version": "5.4.47",

View File

@ -5,58 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.4.60 - _November 16, 2023_
* Dependencies updated
## v5.4.59 - _August 29, 2023_
* Dependencies updated
## v5.4.58 - _August 18, 2023_
* Dependencies updated
## v5.4.57 - _August 9, 2023_
* Dependencies updated
## v5.4.56 - _July 21, 2023_
* Dependencies updated
## v5.4.55 - _July 19, 2023_
* Dependencies updated
## v5.4.54 - _May 10, 2023_
* Dependencies updated
## v5.4.53 - _May 1, 2023_
* Dependencies updated
## v5.4.52 - _April 20, 2023_
* Dependencies updated
## v5.4.51 - _April 17, 2023_
* Dependencies updated
## v5.4.50 - _April 10, 2023_
* Dependencies updated
## v5.4.49 - _March 10, 2023_
* Dependencies updated
## v5.4.48 - _March 1, 2023_
* Dependencies updated
## v5.4.47 - _February 1, 2023_
* Dependencies updated

View File

@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.4.60",
"version": "5.4.47",
"engines": {
"node": ">=6.12"
},
@ -39,19 +39,19 @@
"typescript": "4.6.3"
},
"dependencies": {
"@0x/assert": "^3.0.36",
"@0x/assert": "^3.0.35",
"@0x/base-contract": "^7.0.0",
"@0x/contract-addresses": "^8.13.0",
"@0x/dev-utils": "^5.0.2",
"@0x/contract-addresses": "^8.0.3",
"@0x/dev-utils": "^5.0.0",
"@0x/json-schemas": "^6.4.4",
"@0x/order-utils": "^10.4.28",
"@0x/sol-profiler": "^4.1.36",
"@0x/sol-trace": "^3.0.46",
"@0x/subproviders": "^8.0.1",
"@0x/types": "^3.3.7",
"@0x/subproviders": "^7.0.0",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^7.0.0",
"@0x/web3-wrapper": "^8.0.1",
"@0x/web3-wrapper": "^8.0.0",
"@types/bn.js": "^4.11.0",
"@types/js-combinatorics": "^0.5.29",
"@types/lodash": "4.14.104",

View File

@ -1,9 +1,12 @@
import { devConstants, env, EnvVars, Web3Config, web3Factory } from '@0x/dev-utils';
import { Web3ProviderEngine } from '@0x/subproviders';
import { prependSubprovider, Web3ProviderEngine } from '@0x/subproviders';
import { logUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import { constants } from './constants';
import { profiler } from './profiler';
import { revertTrace } from './revert_trace';
export const txDefaults = {
from: devConstants.TESTRPC_FIRST_ADDRESS,
@ -28,9 +31,26 @@ export const providerConfigs: Web3Config = {
export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs);
provider.stop();
const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
const enabledSubproviderCount = _.filter([isCoverageEnabled], _.identity.bind(_)).length;
const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler);
const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace);
const enabledSubproviderCount = _.filter(
[isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled],
_.identity.bind(_),
).length;
if (enabledSubproviderCount > 1) {
throw new Error(`Only one of profiler or revert trace subproviders can be enabled at a time`);
}
if (isProfilerEnabled) {
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
logUtils.log(
"By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
);
profilerSubprovider.stop();
prependSubprovider(provider, profilerSubprovider);
}
if (isRevertTraceEnabled) {
const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton();
prependSubprovider(provider, revertTraceSubprovider);
}
export const web3Wrapper = new Web3Wrapper(provider);

View File

@ -1,130 +1,4 @@
[
{
"timestamp": 1700094997,
"version": "1.4.54",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1693346928,
"version": "1.4.53",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1692368658,
"version": "1.4.52",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1691617396,
"version": "1.4.51",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689974915,
"version": "1.4.50",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689791426,
"version": "1.4.49",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1683749017,
"version": "1.4.48",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1682976338,
"version": "1.4.47",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1682334742,
"version": "1.4.46",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681969282,
"version": "1.4.45",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681697326,
"version": "1.4.44",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.4.43",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1681157139
},
{
"timestamp": 1678410794,
"version": "1.4.42",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1677693479,
"version": "1.4.41",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1675210931,
"version": "1.4.40",

View File

@ -5,62 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.4.54 - _November 16, 2023_
* Dependencies updated
## v1.4.53 - _August 29, 2023_
* Dependencies updated
## v1.4.52 - _August 18, 2023_
* Dependencies updated
## v1.4.51 - _August 9, 2023_
* Dependencies updated
## v1.4.50 - _July 21, 2023_
* Dependencies updated
## v1.4.49 - _July 19, 2023_
* Dependencies updated
## v1.4.48 - _May 10, 2023_
* Dependencies updated
## v1.4.47 - _May 1, 2023_
* Dependencies updated
## v1.4.46 - _April 24, 2023_
* Dependencies updated
## v1.4.45 - _April 20, 2023_
* Dependencies updated
## v1.4.44 - _April 17, 2023_
* Dependencies updated
## v1.4.43 - _April 10, 2023_
* Dependencies updated
## v1.4.42 - _March 10, 2023_
* Dependencies updated
## v1.4.41 - _March 1, 2023_
* Dependencies updated
## v1.4.40 - _February 1, 2023_
* Dependencies updated

View File

@ -1,6 +1,6 @@
{
"name": "@0x/contracts-treasury",
"version": "1.4.54",
"version": "1.4.40",
"engines": {
"node": ">=6.12"
},
@ -45,13 +45,13 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
"devDependencies": {
"@0x/abi-gen": "^5.8.5",
"@0x/contract-addresses": "^8.13.0",
"@0x/abi-gen": "^5.8.1",
"@0x/contract-addresses": "^8.0.3",
"@0x/contracts-asset-proxy": "^3.7.19",
"@0x/contracts-erc20": "3.3.57",
"@0x/contracts-gen": "^2.0.50",
"@0x/contracts-gen": "^2.0.48",
"@0x/contracts-staking": "^2.0.45",
"@0x/contracts-test-utils": "^5.4.60",
"@0x/contracts-test-utils": "^5.4.47",
"@0x/sol-compiler": "^4.8.2",
"@0x/ts-doc-gen": "^0.0.28",
"@types/isomorphic-fetch": "^0.0.35",
@ -73,12 +73,12 @@
},
"dependencies": {
"@0x/base-contract": "^7.0.0",
"@0x/protocol-utils": "^11.24.2",
"@0x/subproviders": "^8.0.1",
"@0x/types": "^3.3.7",
"@0x/protocol-utils": "^11.17.6",
"@0x/subproviders": "^7.0.0",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^7.0.0",
"@0x/web3-wrapper": "^8.0.1",
"@0x/web3-wrapper": "^8.0.0",
"ethereum-types": "^3.7.1",
"ethereumjs-util": "^7.0.10"
},

View File

@ -1,130 +1,4 @@
[
{
"timestamp": 1700094997,
"version": "4.8.52",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1693346928,
"version": "4.8.51",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1692368658,
"version": "4.8.50",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1691617396,
"version": "4.8.49",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689974915,
"version": "4.8.48",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1689791426,
"version": "4.8.47",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1683749017,
"version": "4.8.46",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1682976338,
"version": "4.8.45",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1681969282,
"version": "4.8.44",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.8.43",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1681756154
},
{
"timestamp": 1681697326,
"version": "4.8.42",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.8.41",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1681157139
},
{
"timestamp": 1678410794,
"version": "4.8.40",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1677693479,
"version": "4.8.39",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1675210931,
"version": "4.8.38",

View File

@ -5,62 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.8.52 - _November 16, 2023_
* Dependencies updated
## v4.8.51 - _August 29, 2023_
* Dependencies updated
## v4.8.50 - _August 18, 2023_
* Dependencies updated
## v4.8.49 - _August 9, 2023_
* Dependencies updated
## v4.8.48 - _July 21, 2023_
* Dependencies updated
## v4.8.47 - _July 19, 2023_
* Dependencies updated
## v4.8.46 - _May 10, 2023_
* Dependencies updated
## v4.8.45 - _May 1, 2023_
* Dependencies updated
## v4.8.44 - _April 20, 2023_
* Dependencies updated
## v4.8.43 - _April 17, 2023_
* Dependencies updated
## v4.8.42 - _April 17, 2023_
* Dependencies updated
## v4.8.41 - _April 10, 2023_
* Dependencies updated
## v4.8.40 - _March 10, 2023_
* Dependencies updated
## v4.8.39 - _March 1, 2023_
* Dependencies updated
## v4.8.38 - _February 1, 2023_
* Dependencies updated

View File

@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.8.52",
"version": "4.8.38",
"engines": {
"node": ">=6.12"
},
@ -15,6 +15,7 @@
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"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",
@ -43,14 +44,14 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/utils",
"devDependencies": {
"@0x/abi-gen": "^5.8.5",
"@0x/contracts-gen": "^2.0.50",
"@0x/contracts-test-utils": "^5.4.60",
"@0x/dev-utils": "^5.0.2",
"@0x/abi-gen": "^5.8.1",
"@0x/contracts-gen": "^2.0.48",
"@0x/contracts-test-utils": "^5.4.47",
"@0x/dev-utils": "^5.0.0",
"@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.8.2",
"@0x/types": "^3.3.7",
"@0x/web3-wrapper": "^8.0.1",
"@0x/types": "^3.3.6",
"@0x/web3-wrapper": "^8.0.0",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",

View File

@ -1,150 +1,11 @@
[
{
"version": "0.49.0",
"changes": [
{
"note": "Allowlist Sepolia in AbstractBridgeAdapter"
}
],
"timestamp": 1700094997
},
{
"version": "0.48.0",
"changes": [
{
"note": "Add VelodromeV2 support on Base"
}
],
"timestamp": 1693346928
},
{
"version": "0.47.0",
"changes": [
{
"note": "Add MaverickV1 support on Ethereum, BSC, and Base"
}
],
"timestamp": 1692368658
},
{
"version": "0.46.0",
"changes": [
{
"note": "Add VelodromeV2 support on Optimism"
}
],
"timestamp": 1691617396
},
{
"timestamp": 1689974915,
"version": "0.45.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.45.0",
"changes": [
{
"note": "Remove Bancor V1 support"
},
{
"note": "Remove Shell and MStable support"
},
{
"note": "Add Base Mainnet and Goerli BridgeAdapters"
},
{
"note": "Add Uniswap V3 support on Avalanche and BSC"
}
],
"timestamp": 1689791426
},
{
"version": "0.44.0",
"changes": [
{
"note": "Add Trader Joe V2 MixIn to Arbitrum"
}
],
"timestamp": 1683749017
},
{
"version": "0.43.0",
"changes": [
{
"note": "Add Trader Joe V2.1 Router Support for MixIn"
}
],
"timestamp": 1682976338
},
{
"timestamp": 1682334742,
"version": "0.42.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.42.0",
"changes": [
{
"note": "Add Trader Joe V2 support on Avalanche"
}
],
"timestamp": 1681969282
},
{
"version": "0.41.0",
"changes": [
{
"note": "Add Barter support on Ethereum"
}
],
"timestamp": 1681756154
},
{
"version": "0.40.0",
"changes": [
{
"note": "Add Barter support on Ethereum"
}
],
"timestamp": 1681697326
},
{
"version": "0.39.2",
"changes": [
{
"note": "Uprgade dependencies"
}
],
"timestamp": 1681157139
},
{
"version": "0.39.1",
"changes": [
{
"note": "Add KyberElastic mixin for Optimism and BSC"
}
],
"timestamp": 1678410794
},
{
"version": "0.39.0",
"changes": [
{
"note": "Add KyberElastic mixin for Ethereum, Polygon, Arbitrum, Avalanche"
},
{
"note": "Skip chain id validation in AbstractBridgeAdapter on testnets"
}
],
"timestamp": 1677693479
]
},
{
"timestamp": 1675210931,

View File

@ -5,70 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.49.0 - _November 16, 2023_
* Allowlist Sepolia in AbstractBridgeAdapter
## v0.48.0 - _August 29, 2023_
* Add VelodromeV2 support on Base
## v0.47.0 - _August 18, 2023_
* Add MaverickV1 support on Ethereum, BSC, and Base
## v0.46.0 - _August 9, 2023_
* Add VelodromeV2 support on Optimism
## v0.45.1 - _July 21, 2023_
* Dependencies updated
## v0.45.0 - _July 19, 2023_
* Remove Bancor V1 support
* Remove Shell and MStable support
* Add Base Mainnet and Goerli BridgeAdapters
* Add Uniswap V3 support on Avalanche and BSC
## v0.44.0 - _May 10, 2023_
* Add Trader Joe V2 MixIn to Arbitrum
## v0.43.0 - _May 1, 2023_
* Add Trader Joe V2.1 Router Support for MixIn
## v0.42.1 - _April 24, 2023_
* Dependencies updated
## v0.42.0 - _April 20, 2023_
* Add Trader Joe V2 support on Avalanche
## v0.41.0 - _April 17, 2023_
* Add Barter support on Ethereum
## v0.40.0 - _April 17, 2023_
* Add Barter support on Ethereum
## v0.39.2 - _April 10, 2023_
* Uprgade dependencies
## v0.39.1 - _March 10, 2023_
* Add KyberElastic mixin for Optimism and BSC
## v0.39.0 - _March 1, 2023_
* Add KyberElastic mixin for Ethereum, Polygon, Arbitrum, Avalanche
* Skip chain id validation in AbstractBridgeAdapter on testnets
## v0.38.6 - _February 1, 2023_
* Dependencies updated

View File

@ -31,7 +31,6 @@
"./contracts/src/features/FundRecoveryFeature.sol",
"./contracts/src/features/LiquidityProviderFeature.sol",
"./contracts/src/features/MetaTransactionsFeature.sol",
"./contracts/src/features/MetaTransactionsFeatureV2.sol",
"./contracts/src/features/NativeOrdersFeature.sol",
"./contracts/src/features/OtcOrdersFeature.sol",
"./contracts/src/features/OwnableFeature.sol",
@ -49,7 +48,6 @@
"./contracts/src/features/interfaces/IFundRecoveryFeature.sol",
"./contracts/src/features/interfaces/ILiquidityProviderFeature.sol",
"./contracts/src/features/interfaces/IMetaTransactionsFeature.sol",
"./contracts/src/features/interfaces/IMetaTransactionsFeatureV2.sol",
"./contracts/src/features/interfaces/IMultiplexFeature.sol",
"./contracts/src/features/interfaces/INativeOrdersEvents.sol",
"./contracts/src/features/interfaces/INativeOrdersFeature.sol",
@ -115,8 +113,6 @@
"./contracts/src/transformers/bridges/ArbitrumBridgeAdapter.sol",
"./contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol",
"./contracts/src/transformers/bridges/BSCBridgeAdapter.sol",
"./contracts/src/transformers/bridges/BaseBridgeAdapter.sol",
"./contracts/src/transformers/bridges/BaseGoerliBridgeAdapter.sol",
"./contracts/src/transformers/bridges/BridgeProtocols.sol",
"./contracts/src/transformers/bridges/CeloBridgeAdapter.sol",
"./contracts/src/transformers/bridges/EthereumBridgeAdapter.sol",
@ -127,6 +123,7 @@
"./contracts/src/transformers/bridges/mixins/MixinAaveV2.sol",
"./contracts/src/transformers/bridges/mixins/MixinBalancer.sol",
"./contracts/src/transformers/bridges/mixins/MixinBalancerV2Batch.sol",
"./contracts/src/transformers/bridges/mixins/MixinBancor.sol",
"./contracts/src/transformers/bridges/mixins/MixinBancorV3.sol",
"./contracts/src/transformers/bridges/mixins/MixinCompound.sol",
"./contracts/src/transformers/bridges/mixins/MixinCryptoCom.sol",
@ -137,10 +134,12 @@
"./contracts/src/transformers/bridges/mixins/MixinGMX.sol",
"./contracts/src/transformers/bridges/mixins/MixinKyberDmm.sol",
"./contracts/src/transformers/bridges/mixins/MixinLido.sol",
"./contracts/src/transformers/bridges/mixins/MixinMStable.sol",
"./contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol",
"./contracts/src/transformers/bridges/mixins/MixinMooniswap.sol",
"./contracts/src/transformers/bridges/mixins/MixinNerve.sol",
"./contracts/src/transformers/bridges/mixins/MixinPlatypus.sol",
"./contracts/src/transformers/bridges/mixins/MixinShell.sol",
"./contracts/src/transformers/bridges/mixins/MixinSolidly.sol",
"./contracts/src/transformers/bridges/mixins/MixinSynthetix.sol",
"./contracts/src/transformers/bridges/mixins/MixinUniswap.sol",

@ -1 +1 @@
Subproject commit fc560fa34fa12a335a50c35d92e55a6628ca467c
Subproject commit 058d2004ac10cc8f194625fb107fb7a87c4e702d

View File

@ -23,16 +23,8 @@ abstract contract AbstractBridgeAdapter is IBridgeAdapter {
assembly {
chainId := chainid()
}
// Skip chain id validation on Ganache (1337), Anvil (31337), Goerli (5), Mumbai (80001), Base Goerli (84531),
// Sepolia (11155111)
bool skipValidation = (chainId == 1337 ||
chainId == 31337 ||
chainId == 5 ||
chainId == 80001 ||
chainId == 84531 ||
chainId == 11155111);
if (chainId != expectedChainId && !skipValidation) {
// Allow testing on Ganache
if (chainId != expectedChainId && chainId != 1337) {
revert(string(abi.encodePacked(expectedChainName, "BridgeAdapter.constructor: wrong chain ID")));
}
}

View File

@ -26,7 +26,6 @@ import "./mixins/MixinKyberDmm.sol";
import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinGMX.sol";
import "./mixins/MixinNerve.sol";
import "./mixins/MixinTraderJoeV2.sol";
import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinWOOFi.sol";
@ -43,13 +42,12 @@ contract ArbitrumBridgeAdapter is
MixinKyberElastic,
MixinGMX,
MixinNerve,
MixinTraderJoeV2,
MixinUniswapV3,
MixinUniswapV2,
MixinWOOFi,
MixinZeroExBridge
{
constructor(IEtherToken weth) public MixinCurve(weth) {}
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(true) {}
function _trade(
BridgeOrder memory order,
@ -99,11 +97,6 @@ contract ArbitrumBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.TRADERJOEV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeTraderJoeV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.GMX) {
if (dryRun) {
return (0, true);

View File

@ -26,9 +26,7 @@ import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinAaveV2.sol";
import "./mixins/MixinNerve.sol";
import "./mixins/MixinPlatypus.sol";
import "./mixins/MixinTraderJoeV2.sol";
import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol";
@ -43,13 +41,11 @@ contract AvalancheBridgeAdapter is
MixinAaveV2,
MixinNerve,
MixinPlatypus,
MixinTraderJoeV2,
MixinUniswapV2,
MixinUniswapV3,
MixinWOOFi,
MixinZeroExBridge
{
constructor(IEtherToken weth) public MixinCurve(weth) {}
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(false) {}
function _trade(
BridgeOrder memory order,
@ -74,11 +70,6 @@ contract AvalancheBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeUniswapV3(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.NERVE) {
if (dryRun) {
return (0, true);
@ -109,11 +100,6 @@ contract AvalancheBridgeAdapter is
return (0, true);
}
boughtAmount = _tradePlatypus(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.TRADERJOEV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeTraderJoeV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) {
return (0, true);

View File

@ -21,12 +21,9 @@ import "./mixins/MixinCurve.sol";
import "./mixins/MixinDodo.sol";
import "./mixins/MixinDodoV2.sol";
import "./mixins/MixinKyberDmm.sol";
import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinMaverickV1.sol";
import "./mixins/MixinMooniswap.sol";
import "./mixins/MixinNerve.sol";
import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol";
@ -36,12 +33,9 @@ contract BSCBridgeAdapter is
MixinDodo,
MixinDodoV2,
MixinKyberDmm,
MixinKyberElastic,
MixinMaverickV1,
MixinMooniswap,
MixinNerve,
MixinUniswapV2,
MixinUniswapV3,
MixinWOOFi,
MixinZeroExBridge
{
@ -65,11 +59,6 @@ contract BSCBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeUniswapV3(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.MOONISWAP) {
if (dryRun) {
return (0, true);
@ -95,21 +84,11 @@ contract BSCBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeKyberDmm(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.KYBERELASTIC) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeKyberElastic(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeWOOFi(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.MAVERICKV1) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeMaverickV1(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) {
return (0, true);

View File

@ -1,93 +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 "./AbstractBridgeAdapter.sol";
import "./BridgeProtocols.sol";
import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinBalancerV2Batch.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinCurveV2.sol";
import "./mixins/MixinMaverickV1.sol";
import "./mixins/MixinSolidly.sol";
import "./mixins/MixinVelodromeV2.sol";
contract BaseBridgeAdapter is
AbstractBridgeAdapter(8453, "Base"),
MixinUniswapV3,
MixinUniswapV2,
MixinBalancerV2Batch,
MixinCurve,
MixinCurveV2,
MixinMaverickV1,
MixinSolidly,
MixinVelodromeV2
{
constructor(IEtherToken weth) public MixinCurve(weth) {}
function _trade(
BridgeOrder memory order,
IERC20Token sellToken,
IERC20Token buyToken,
uint256 sellAmount,
bool dryRun
) internal override returns (uint256 boughtAmount, bool supportedSource) {
uint128 protocolId = uint128(uint256(order.source) >> 128);
if (protocolId == BridgeProtocols.CURVE) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeCurve(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.CURVEV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeCurveV2(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNISWAPV3) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeUniswapV3(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.SOLIDLY) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeSolidly(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.BALANCERV2BATCH) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeBalancerV2Batch(sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.MAVERICKV1) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeMaverickV1(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.VELODROMEV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeVelodromeV2(sellToken, sellAmount, order.bridgeData);
}
emit BridgeFill(order.source, sellToken, buyToken, sellAmount, boughtAmount);
}
}

View File

@ -1,45 +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 "./AbstractBridgeAdapter.sol";
import "./BridgeProtocols.sol";
import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinUniswapV2.sol";
contract BaseGoerliBridgeAdapter is AbstractBridgeAdapter(84531, "Base Goerli"), MixinUniswapV3, MixinUniswapV2 {
function _trade(
BridgeOrder memory order,
IERC20Token sellToken,
IERC20Token buyToken,
uint256 sellAmount,
bool dryRun
) internal override returns (uint256 boughtAmount, bool supportedSource) {
uint128 protocolId = uint128(uint256(order.source) >> 128);
if (protocolId == BridgeProtocols.UNISWAPV3) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeUniswapV3(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNISWAPV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeUniswapV2(buyToken, sellAmount, order.bridgeData);
}
emit BridgeFill(order.source, sellToken, buyToken, sellAmount, boughtAmount);
}
}

View File

@ -55,8 +55,4 @@ library BridgeProtocols {
uint128 internal constant WOOFI = 31;
uint128 internal constant AAVEV3 = 32;
uint128 internal constant KYBERELASTIC = 33;
uint128 internal constant BARTER = 34;
uint128 internal constant TRADERJOEV2 = 35;
uint128 internal constant VELODROMEV2 = 36;
uint128 internal constant MAVERICKV1 = 37;
}

View File

@ -20,8 +20,8 @@ import "./BridgeProtocols.sol";
import "./mixins/MixinAaveV2.sol";
import "./mixins/MixinBalancer.sol";
import "./mixins/MixinBalancerV2Batch.sol";
import "./mixins/MixinBancor.sol";
import "./mixins/MixinBancorV3.sol";
import "./mixins/MixinBarter.sol";
import "./mixins/MixinCompound.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinCurveV2.sol";
@ -32,8 +32,9 @@ import "./mixins/MixinKyberDmm.sol";
import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinLido.sol";
import "./mixins/MixinMakerPSM.sol";
import "./mixins/MixinMaverickV1.sol";
import "./mixins/MixinMStable.sol";
import "./mixins/MixinNerve.sol";
import "./mixins/MixinShell.sol";
import "./mixins/MixinSynthetix.sol";
import "./mixins/MixinUniswap.sol";
import "./mixins/MixinUniswapV2.sol";
@ -45,8 +46,8 @@ contract EthereumBridgeAdapter is
MixinAaveV2,
MixinBalancer,
MixinBalancerV2Batch,
MixinBancor,
MixinBancorV3,
MixinBarter,
MixinCompound,
MixinCurve,
MixinCurveV2,
@ -57,8 +58,9 @@ contract EthereumBridgeAdapter is
MixinKyberElastic,
MixinLido,
MixinMakerPSM,
MixinMaverickV1,
MixinMStable,
MixinNerve,
MixinShell,
MixinSynthetix,
MixinUniswap,
MixinUniswapV2,
@ -67,7 +69,15 @@ contract EthereumBridgeAdapter is
{
constructor(
IEtherToken weth
) public MixinBancorV3(weth) MixinCompound(weth) MixinCurve(weth) MixinLido(weth) MixinUniswap(weth) {}
)
public
MixinBancor(weth)
MixinBancorV3(weth)
MixinCompound(weth)
MixinCurve(weth)
MixinLido(weth)
MixinUniswap(weth)
{}
function _trade(
BridgeOrder memory order,
@ -117,6 +127,16 @@ contract EthereumBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeMakerPsm(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.MSTABLE) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeMStable(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.SHELL) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeShell(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.DODO) {
if (dryRun) {
return (0, true);
@ -132,6 +152,11 @@ contract EthereumBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeCryptoCom(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.BANCOR) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeBancor(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.NERVE) {
if (dryRun) {
return (0, true);
@ -172,16 +197,6 @@ contract EthereumBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeSynthetix(sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.BARTER) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeBarter(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.MAVERICKV1) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeMaverickV1(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) {
return (0, true);

View File

@ -21,12 +21,10 @@ import "./mixins/MixinAaveV3.sol";
import "./mixins/MixinBalancerV2Batch.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinCurveV2.sol";
import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinNerve.sol";
import "./mixins/MixinSolidly.sol";
import "./mixins/MixinSynthetix.sol";
import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinVelodromeV2.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol";
@ -36,16 +34,14 @@ contract OptimismBridgeAdapter is
MixinBalancerV2Batch,
MixinCurve,
MixinCurveV2,
MixinKyberElastic,
MixinNerve,
MixinSynthetix,
MixinUniswapV3,
MixinVelodromeV2,
MixinSolidly,
MixinWOOFi,
MixinZeroExBridge
{
constructor(IEtherToken weth) public MixinCurve(weth) {}
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(true) {}
/* solhint-disable function-max-lines */
function _trade(
@ -106,16 +102,6 @@ contract OptimismBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeWOOFi(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.KYBERELASTIC) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeKyberElastic(sellToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.VELODROMEV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeVelodromeV2(sellToken, sellAmount, order.bridgeData);
}
emit BridgeFill(order.source, sellToken, buyToken, sellAmount, boughtAmount);

View File

@ -26,6 +26,7 @@ import "./mixins/MixinDodo.sol";
import "./mixins/MixinDodoV2.sol";
import "./mixins/MixinKyberDmm.sol";
import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinMStable.sol";
import "./mixins/MixinNerve.sol";
import "./mixins/MixinSolidly.sol";
import "./mixins/MixinUniswapV2.sol";
@ -44,6 +45,7 @@ contract PolygonBridgeAdapter is
MixinDodoV2,
MixinKyberDmm,
MixinKyberElastic,
MixinMStable,
MixinNerve,
MixinUniswapV2,
MixinUniswapV3,
@ -51,7 +53,7 @@ contract PolygonBridgeAdapter is
MixinWOOFi,
MixinZeroExBridge
{
constructor(IEtherToken weth) public MixinCurve(weth) {}
constructor(IEtherToken weth) public MixinCurve(weth) MixinAaveV3(false) {}
function _trade(
BridgeOrder memory order,
@ -86,6 +88,11 @@ contract PolygonBridgeAdapter is
return (0, true);
}
boughtAmount = _tradeBalancerV2Batch(sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.MSTABLE) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeMStable(sellToken, buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.DODO) {
if (dryRun) {
return (0, true);

View File

@ -47,16 +47,63 @@ interface IPool {
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
}
// Minimal Aave V3 L2Pool interface
interface IL2Pool {
/**
* @notice Calldata efficient wrapper of the supply function on behalf of the caller
* @param args Arguments for the supply function packed in one bytes32
* 96 bits 16 bits 128 bits 16 bits
* | 0-padding | referralCode | shortenedAmount | assetId |
* @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to
* type(uint256).max
* @dev assetId is the index of the asset in the reservesList.
*/
function supply(bytes32 args) external;
/**
* @notice Calldata efficient wrapper of the withdraw function, withdrawing to the caller
* @param args Arguments for the withdraw function packed in one bytes32
* 112 bits 128 bits 16 bits
* | 0-padding | shortenedAmount | assetId |
* @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to
* type(uint256).max
* @dev assetId is the index of the asset in the reservesList.
*/
function withdraw(bytes32 args) external;
}
contract MixinAaveV3 {
using LibERC20TokenV06 for IERC20Token;
bool private immutable _isL2;
constructor(bool isL2) public {
_isL2 = isL2;
}
function _tradeAaveV3(
IERC20Token sellToken,
IERC20Token buyToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256) {
(IPool pool, address aToken) = abi.decode(bridgeData, (IPool, address));
if (_isL2) {
(IL2Pool pool, address aToken, bytes32 l2Params) = abi.decode(bridgeData, (IL2Pool, address, bytes32));
sellToken.approveIfBelow(address(pool), sellAmount);
if (address(buyToken) == aToken) {
pool.supply(l2Params);
// 1:1 mapping token --> aToken and have the same number of decimals as the underlying token
return sellAmount;
} else if (address(sellToken) == aToken) {
pool.withdraw(l2Params);
return sellAmount;
}
revert("MixinAaveV3/UNSUPPORTED_TOKEN_PAIR");
}
(IPool pool, address aToken, ) = abi.decode(bridgeData, (IPool, address, bytes32));
sellToken.approveIfBelow(address(pool), sellAmount);

View File

@ -0,0 +1,93 @@
// 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 "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "../IBridgeAdapter.sol";
interface IBancorNetwork {
function convertByPath(
IERC20Token[] calldata _path,
uint256 _amount,
uint256 _minReturn,
address _beneficiary,
address _affiliateAccount,
uint256 _affiliateFee
) external payable returns (uint256);
}
contract MixinBancor {
/// @dev Bancor ETH pseudo-address.
IERC20Token public constant BANCOR_ETH_ADDRESS = IERC20Token(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
IEtherToken private immutable WETH;
constructor(IEtherToken weth) public {
WETH = weth;
}
function _tradeBancor(
IERC20Token buyToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
// Decode the bridge data.
IBancorNetwork bancorNetworkAddress;
IERC20Token[] memory path;
{
address[] memory _path;
(bancorNetworkAddress, _path) = abi.decode(bridgeData, (IBancorNetwork, address[]));
// To get around `abi.decode()` not supporting interface array types.
assembly {
path := _path
}
}
require(path.length >= 2, "MixinBancor/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == buyToken || (path[path.length - 1] == BANCOR_ETH_ADDRESS && buyToken == WETH),
"MixinBancor/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
uint256 payableAmount = 0;
// If it's ETH in the path then withdraw from WETH
// The Bancor path will have ETH as the 0xeee address
// Bancor expects to be paid in ETH not WETH
if (path[0] == BANCOR_ETH_ADDRESS) {
WETH.withdraw(sellAmount);
payableAmount = sellAmount;
} else {
// Grant an allowance to the Bancor Network.
LibERC20TokenV06.approveIfBelow(path[0], address(bancorNetworkAddress), sellAmount);
}
// Convert the tokens
boughtAmount = bancorNetworkAddress.convertByPath{value: payableAmount}(
path, // path originating with source token and terminating in destination token
sellAmount, // amount of source token to trade
1, // minimum amount of destination token expected to receive
address(this), // beneficiary
address(0), // affiliateAccount; no fee paid
0 // affiliateFee; no fee paid
);
if (path[path.length - 1] == BANCOR_ETH_ADDRESS) {
WETH.deposit{value: boughtAmount}();
}
return boughtAmount;
}
}

View File

@ -1,63 +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 "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
interface IMaverickV1Router {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
address pool;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint256 sqrtPriceLimitD18;
}
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}
contract MixinMaverickV1 {
using LibERC20TokenV06 for IERC20Token;
function _tradeMaverickV1(
IERC20Token sellToken,
IERC20Token buyToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
(IMaverickV1Router router, address pool) = abi.decode(bridgeData, (IMaverickV1Router, address));
// Grant the MaverickV1 router an allowance to sell the sellToken
sellToken.approveIfBelow(address(router), sellAmount);
boughtAmount = router.exactInputSingle(
IMaverickV1Router.ExactInputSingleParams({
tokenIn: address(sellToken),
tokenOut: address(buyToken),
pool: pool,
recipient: address(this),
deadline: block.timestamp,
amountIn: sellAmount,
amountOutMinimum: 1,
sqrtPriceLimitD18: 0
})
);
}
}

View File

@ -17,25 +17,41 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
contract MixinBarter {
interface IShell {
function originSwap(
IERC20Token from,
IERC20Token to,
uint256 fromAmount,
uint256 minTargetAmount,
uint256 deadline
) external returns (uint256 toAmount);
}
contract MixinShell {
using LibERC20TokenV06 for IERC20Token;
using LibRichErrorsV06 for bytes;
function _tradeBarter(
function _tradeShell(
IERC20Token sellToken,
IERC20Token buyToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
(address barterRouter, bytes memory data) = abi.decode(bridgeData, (address, bytes));
sellToken.approveIfBelow(barterRouter, sellAmount);
IShell pool = abi.decode(bridgeData, (IShell));
(bool success, bytes memory resultData) = barterRouter.call(data);
if (!success) {
resultData.rrevert();
}
// Grant the Shell contract an allowance to sell the first token.
IERC20Token(sellToken).approveIfBelow(address(pool), sellAmount);
return abi.decode(resultData, (uint256));
boughtAmount = pool.originSwap(
sellToken,
buyToken,
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.
1,
// deadline
block.timestamp + 1
);
return boughtAmount;
}
}

View File

@ -1,112 +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 "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "../IBridgeAdapter.sol";
interface ILBRouter {
/**
* @dev This enum represents the version of the pair requested
* - V1: Joe V1 pair
* - V2: LB pair V2. Also called legacyPair
* - V2_1: LB pair V2.1 (current version)
*/
enum Version {
V1,
V2,
V2_1
}
/**
* @dev The path parameters, such as:
* - pairBinSteps: The list of bin steps of the pairs to go through
* - versions: The list of versions of the pairs to go through
* - tokenPath: The list of tokens in the path to go through
*/
struct Path {
uint256[] pairBinSteps;
Version[] versions;
IERC20Token[] tokenPath;
}
/**
* @notice Swaps exact tokens for tokens while performing safety checks
* @param amountIn The amount of token to send
* @param amountOutMin The min amount of token to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external returns (uint256 amountOut);
}
contract MixinTraderJoeV2 {
using LibERC20TokenV06 for IERC20Token;
function _tradeTraderJoeV2(
IERC20Token buyToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
ILBRouter router;
IERC20Token[] memory tokenPath;
uint256[] memory pairBinSteps;
ILBRouter.Version[] memory versions;
{
address[] memory _tokenPath;
(router, _tokenPath, pairBinSteps, versions) = abi.decode(
bridgeData,
(ILBRouter, address[], uint256[], ILBRouter.Version[])
);
// To get around `abi.decode()` not supporting interface array types.
assembly {
tokenPath := _tokenPath
}
}
require(tokenPath.length >= 2, "MixinTraderJoeV2/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
tokenPath.length == pairBinSteps.length + 1,
"MixinTraderJoeV2/PAIR_BIN_STEPS_LENGTH_MUST_BE_ONE_LESS_THAN_TOKEN_PATH_LENGTH"
);
require(
versions.length == pairBinSteps.length,
"MixinTraderJoeV2/VERSIONS_LENGTH_MUST_BE_EQUAL_TO_PAIR_BIN_STEPS_LENGTH"
);
require(
tokenPath[tokenPath.length - 1] == buyToken,
"MixinTraderJoeV2/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the Trader Joe V2 router an allowance to sell the first token.
tokenPath[0].approveIfBelow(address(router), sellAmount);
ILBRouter.Path memory path = ILBRouter.Path({
pairBinSteps: pairBinSteps,
versions: versions,
tokenPath: tokenPath
});
boughtAmount = router.swapExactTokensForTokens(sellAmount, 1, path, address(this), block.timestamp);
}
}

View File

@ -31,18 +31,6 @@ interface IUniswapV3Router {
function exactInput(ExactInputParams memory params) external payable returns (uint256 amountOut);
}
// https://github.com/Uniswap/swap-router-contracts/blob/main/contracts/interfaces/IV3SwapRouter.sol
interface IUniswapV3Router2 {
struct ExactInputParams {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(ExactInputParams memory params) external payable returns (uint256 amountOut);
}
contract MixinUniswapV3 {
using LibERC20TokenV06 for IERC20Token;
@ -51,30 +39,19 @@ contract MixinUniswapV3 {
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
(address router, bytes memory path, uint256 routerVersion) = abi.decode(bridgeData, (address, bytes, uint256));
(IUniswapV3Router router, bytes memory path) = abi.decode(bridgeData, (IUniswapV3Router, bytes));
// Grant the Uniswap router an allowance to sell the sell token.
sellToken.approveIfBelow(router, sellAmount);
sellToken.approveIfBelow(address(router), sellAmount);
if (routerVersion != 2) {
boughtAmount = IUniswapV3Router(router).exactInput(
IUniswapV3Router.ExactInputParams({
path: path,
recipient: address(this),
deadline: block.timestamp,
amountIn: sellAmount,
amountOutMinimum: 1
})
);
} else {
boughtAmount = IUniswapV3Router2(router).exactInput(
IUniswapV3Router2.ExactInputParams({
path: path,
recipient: address(this),
amountIn: sellAmount,
amountOutMinimum: 1
})
);
}
boughtAmount = router.exactInput(
IUniswapV3Router.ExactInputParams({
path: path,
recipient: address(this),
deadline: block.timestamp,
amountIn: sellAmount,
amountOutMinimum: 1
})
);
}
}

View File

@ -1,69 +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 "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
interface IVelodromeV2Router {
struct Route {
address from;
address to;
bool stable;
address factory;
}
/// @notice Swap one token for another
/// @param amountIn Amount of token in
/// @param amountOutMin Minimum amount of desired token received
/// @param routes Array of trade routes used in the swap
/// @param to Recipient of the tokens received
/// @param deadline Deadline to receive tokens
/// @return amounts Array of amounts returned per route
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Route[] calldata routes,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}
contract MixinVelodromeV2 {
using LibERC20TokenV06 for IERC20Token;
function _tradeVelodromeV2(
IERC20Token sellToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
(IVelodromeV2Router router, IVelodromeV2Router.Route[] memory routes) = abi.decode(
bridgeData,
(IVelodromeV2Router, IVelodromeV2Router.Route[])
);
sellToken.approveIfBelow(address(router), sellAmount);
uint256[] memory amounts = router.swapExactTokensForTokens(
sellAmount,
1,
routes,
address(this),
block.timestamp + 1
);
return amounts[amounts.length - 1];
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@0x/contracts-zero-ex",
"version": "0.49.0",
"version": "0.38.6",
"engines": {
"node": ">=6.12"
},
@ -36,9 +36,9 @@
"typechain": "typechain --target=ethers-v5 --out-dir='typechain-wrappers' './foundry-artifacts/**/*.json'"
},
"config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature,AvalancheBridgeAdapter,BaseGoerliBridgeAdapter,BaseBridgeAdapter,BSCBridgeAdapter,CeloBridgeAdapter,EthereumBridgeAdapter,FantomBridgeAdapter,OptimismBridgeAdapter,PolygonBridgeAdapter,MetaTransactionsFeatureV2",
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature,AvalancheBridgeAdapter,BSCBridgeAdapter,CeloBridgeAdapter,EthereumBridgeAdapter,FantomBridgeAdapter,OptimismBridgeAdapter,PolygonBridgeAdapter",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AbstractBridgeAdapter|AffiliateFeeTransformer|ArbitrumBridgeAdapter|AvalancheBridgeAdapter|BSCBridgeAdapter|BaseBridgeAdapter|BaseGoerliBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMetaTransactionsFeatureV2|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MetaTransactionsFeatureV2|MixinAaveV2|MixinBalancer|MixinBalancerV2Batch|MixinBancorV3|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinSolidly|MixinSynthetix|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
"abis": "./test/generated-artifacts/@(AbstractBridgeAdapter|AffiliateFeeTransformer|ArbitrumBridgeAdapter|AvalancheBridgeAdapter|BSCBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2Batch|MixinBancor|MixinBancorV3|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinShell|MixinSolidly|MixinSynthetix|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
},
"repository": {
"type": "git",
@ -50,12 +50,12 @@
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
"devDependencies": {
"@0x/abi-gen": "^5.8.5",
"@0x/contract-addresses": "^8.13.0",
"@0x/abi-gen": "^5.8.1",
"@0x/contract-addresses": "^8.0.3",
"@0x/contracts-erc20": "^3.3.57",
"@0x/contracts-gen": "^2.0.50",
"@0x/contracts-test-utils": "^5.4.60",
"@0x/dev-utils": "^5.0.2",
"@0x/contracts-gen": "^2.0.48",
"@0x/contracts-test-utils": "^5.4.47",
"@0x/dev-utils": "^5.0.0",
"@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.8.2",
"@0x/ts-doc-gen": "^0.0.28",
@ -80,12 +80,12 @@
},
"dependencies": {
"@0x/base-contract": "^7.0.0",
"@0x/protocol-utils": "^11.24.2",
"@0x/subproviders": "^8.0.1",
"@0x/types": "^3.3.7",
"@0x/protocol-utils": "^11.17.6",
"@0x/subproviders": "^7.0.0",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^7.0.0",
"@0x/web3-wrapper": "^8.0.1",
"@0x/web3-wrapper": "^8.0.0",
"ethereum-types": "^3.7.1",
"ethereumjs-util": "^7.0.10",
"ethers": "~4.0.4"

View File

@ -0,0 +1,96 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "forge-std/Script.sol";
import "forge-std/console.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "../contracts/src/external/ILiquidityProviderSandbox.sol";
import '../contracts/src/features/interfaces/IMetaTransactionsFeatureV2.sol';
import '../contracts/src/features/interfaces/IMultiplexFeature.sol';
import '../contracts/src/features/interfaces/IUniswapV3Feature.sol';
import '../contracts/src/features/MetaTransactionsFeatureV2.sol';
import '../contracts/src/features/UniswapV3Feature.sol';
import '../contracts/src/features/multiplex/MultiplexFeature.sol';
contract ContractScript is Script {
struct ChainConfig {
address zeroExAddress;
address wethAddress;
address liquidityProviderSandbox;
address uniswapV3Factory;
address uniswapV2Factory;
address sushiswapFactory;
bytes32 uniswapV3PoolInitCodeHash;
bytes32 uniswapV2PairInitCodeHash;
bytes32 sushiswapPairInitCodeHash;
}
function _getChainConfig() internal pure returns (ChainConfig memory) {
uint256 chainId;
assembly {
chainId := chainid()
}
if (chainId == 1) { // Ethereum
ChainConfig memory chainConfig = ChainConfig(
0xDef1C0ded9bec7F1a1670819833240f027b25EfF, // 0x EP
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, // weth address
0x407B4128E9eCaD8769B2332312a9F655cB9F5F3A, // LP sandbox
0x1F98431c8aD98523631AE4a59f267346ea31F984, // uniswapv3
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, // uniswapv2
0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac, // sushiswap
bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54),
bytes32(0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f),
bytes32(0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303)
);
return chainConfig;
}
if (chainId == 137) { // polygon
ChainConfig memory chainConfig = ChainConfig(
0xDef1C0ded9bec7F1a1670819833240f027b25EfF, // 0x EP
0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270, // wmatic address
0x4Dd97080aDf36103bD3db822f9d3c0e44890fd69, // LP sandbox
0x1F98431c8aD98523631AE4a59f267346ea31F984, // uniswapv3
address(0), // there is no uniswapv2 on polygon
0xc35DADB65012eC5796536bD9864eD8773aBc74C4, // sushiswap
bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54),
bytes32(0), // there is no uniswapv2 on polygon
bytes32(0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303)
);
return chainConfig;
}
revert("unsupported chain");
}
function run() public {
ChainConfig memory chainConfig = _getChainConfig();
vm.startBroadcast();
MetaTransactionsFeatureV2 mtx = new MetaTransactionsFeatureV2(chainConfig.zeroExAddress, IEtherToken(chainConfig.wethAddress));
console.log("MetaTransactionsFeatureV2 address:", address(mtx));
UniswapV3Feature uni = new UniswapV3Feature(
IEtherToken(chainConfig.wethAddress),
chainConfig.uniswapV3Factory,
chainConfig.uniswapV3PoolInitCodeHash
);
console.log("UniswapV3Feature address:", address(uni));
MultiplexFeature multi = new MultiplexFeature(
chainConfig.zeroExAddress,
IEtherToken(chainConfig.wethAddress),
ILiquidityProviderSandbox(chainConfig.liquidityProviderSandbox),
chainConfig.uniswapV2Factory,
chainConfig.sushiswapFactory,
chainConfig.uniswapV2PairInitCodeHash,
chainConfig.sushiswapPairInitCodeHash
);
console.log("MultiplexFeature address:", address(multi));
vm.stopBroadcast();
}
}

View File

@ -1,9 +1,9 @@
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { constants } from '@0x/contracts-test-utils';
import { RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders';
import { RPCSubprovider, SupportedProvider, Web3ProviderEngine } from '@0x/subproviders';
import { AbiEncoder, BigNumber, logUtils, providerUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { MethodAbi, SupportedProvider } from 'ethereum-types';
import { MethodAbi } from 'ethereum-types';
import * as fetch from 'isomorphic-fetch';
import * as _ from 'lodash';
import * as prompts from 'prompts';

View File

@ -7,8 +7,6 @@ import { ContractArtifact } from 'ethereum-types';
import * as AffiliateFeeTransformer from '../generated-artifacts/AffiliateFeeTransformer.json';
import * as AvalancheBridgeAdapter from '../generated-artifacts/AvalancheBridgeAdapter.json';
import * as BaseBridgeAdapter from '../generated-artifacts/BaseBridgeAdapter.json';
import * as BaseGoerliBridgeAdapter from '../generated-artifacts/BaseGoerliBridgeAdapter.json';
import * as BatchFillNativeOrdersFeature from '../generated-artifacts/BatchFillNativeOrdersFeature.json';
import * as BSCBridgeAdapter from '../generated-artifacts/BSCBridgeAdapter.json';
import * as CeloBridgeAdapter from '../generated-artifacts/CeloBridgeAdapter.json';
@ -34,7 +32,6 @@ import * as IZeroEx from '../generated-artifacts/IZeroEx.json';
import * as LiquidityProviderFeature from '../generated-artifacts/LiquidityProviderFeature.json';
import * as LogMetadataTransformer from '../generated-artifacts/LogMetadataTransformer.json';
import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransactionsFeature.json';
import * as MetaTransactionsFeatureV2 from '../generated-artifacts/MetaTransactionsFeatureV2.json';
import * as MultiplexFeature from '../generated-artifacts/MultiplexFeature.json';
import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json';
import * as OptimismBridgeAdapter from '../generated-artifacts/OptimismBridgeAdapter.json';
@ -81,13 +78,10 @@ export const artifacts = {
OtcOrdersFeature: OtcOrdersFeature as ContractArtifact,
IOtcOrdersFeature: IOtcOrdersFeature as ContractArtifact,
AvalancheBridgeAdapter: AvalancheBridgeAdapter as ContractArtifact,
BaseGoerliBridgeAdapter: BaseGoerliBridgeAdapter as ContractArtifact,
BaseBridgeAdapter: BaseBridgeAdapter as ContractArtifact,
BSCBridgeAdapter: BSCBridgeAdapter as ContractArtifact,
CeloBridgeAdapter: CeloBridgeAdapter as ContractArtifact,
EthereumBridgeAdapter: EthereumBridgeAdapter as ContractArtifact,
FantomBridgeAdapter: FantomBridgeAdapter as ContractArtifact,
OptimismBridgeAdapter: OptimismBridgeAdapter as ContractArtifact,
PolygonBridgeAdapter: PolygonBridgeAdapter as ContractArtifact,
MetaTransactionsFeatureV2: MetaTransactionsFeatureV2 as ContractArtifact,
};

View File

@ -26,7 +26,6 @@ export {
RevertErrorAbi,
StandardContractOutput,
StateMutability,
SupportedProvider,
TupleDataItem,
} from 'ethereum-types';
export { artifacts } from './artifacts';
@ -59,3 +58,4 @@ export {
ZeroExContract,
} from './wrappers';
export { EIP712TypedData } from '@0x/types';
export { SupportedProvider } from '@0x/subproviders';

View File

@ -1,6 +1,7 @@
import { SupportedProvider } from '@0x/subproviders';
import { SimpleContractArtifact } from '@0x/types';
import { NULL_ADDRESS } from '@0x/utils';
import { TxData, SupportedProvider } from 'ethereum-types';
import { TxData } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';

View File

@ -6,8 +6,6 @@
export * from '../generated-wrappers/affiliate_fee_transformer';
export * from '../generated-wrappers/avalanche_bridge_adapter';
export * from '../generated-wrappers/b_s_c_bridge_adapter';
export * from '../generated-wrappers/base_bridge_adapter';
export * from '../generated-wrappers/base_goerli_bridge_adapter';
export * from '../generated-wrappers/batch_fill_native_orders_feature';
export * from '../generated-wrappers/celo_bridge_adapter';
export * from '../generated-wrappers/curve_liquidity_provider';
@ -32,7 +30,6 @@ export * from '../generated-wrappers/initial_migration';
export * from '../generated-wrappers/liquidity_provider_feature';
export * from '../generated-wrappers/log_metadata_transformer';
export * from '../generated-wrappers/meta_transactions_feature';
export * from '../generated-wrappers/meta_transactions_feature_v2';
export * from '../generated-wrappers/multiplex_feature';
export * from '../generated-wrappers/native_orders_feature';
export * from '../generated-wrappers/optimism_bridge_adapter';

View File

@ -9,8 +9,6 @@ import * as AbstractBridgeAdapter from '../test/generated-artifacts/AbstractBrid
import * as AffiliateFeeTransformer from '../test/generated-artifacts/AffiliateFeeTransformer.json';
import * as ArbitrumBridgeAdapter from '../test/generated-artifacts/ArbitrumBridgeAdapter.json';
import * as AvalancheBridgeAdapter from '../test/generated-artifacts/AvalancheBridgeAdapter.json';
import * as BaseBridgeAdapter from '../test/generated-artifacts/BaseBridgeAdapter.json';
import * as BaseGoerliBridgeAdapter from '../test/generated-artifacts/BaseGoerliBridgeAdapter.json';
import * as BatchFillNativeOrdersFeature from '../test/generated-artifacts/BatchFillNativeOrdersFeature.json';
import * as BootstrapFeature from '../test/generated-artifacts/BootstrapFeature.json';
import * as BridgeProtocols from '../test/generated-artifacts/BridgeProtocols.json';
@ -53,7 +51,6 @@ import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvi
import * as ILiquidityProviderFeature from '../test/generated-artifacts/ILiquidityProviderFeature.json';
import * as ILiquidityProviderSandbox from '../test/generated-artifacts/ILiquidityProviderSandbox.json';
import * as IMetaTransactionsFeature from '../test/generated-artifacts/IMetaTransactionsFeature.json';
import * as IMetaTransactionsFeatureV2 from '../test/generated-artifacts/IMetaTransactionsFeatureV2.json';
import * as IMooniswapPool from '../test/generated-artifacts/IMooniswapPool.json';
import * as IMultiplexFeature from '../test/generated-artifacts/IMultiplexFeature.json';
import * as INativeOrdersEvents from '../test/generated-artifacts/INativeOrdersEvents.json';
@ -107,10 +104,10 @@ import * as LiquidityProviderFeature from '../test/generated-artifacts/Liquidity
import * as LiquidityProviderSandbox from '../test/generated-artifacts/LiquidityProviderSandbox.json';
import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json';
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
import * as MetaTransactionsFeatureV2 from '../test/generated-artifacts/MetaTransactionsFeatureV2.json';
import * as MixinAaveV2 from '../test/generated-artifacts/MixinAaveV2.json';
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
import * as MixinBalancerV2Batch from '../test/generated-artifacts/MixinBalancerV2Batch.json';
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
import * as MixinBancorV3 from '../test/generated-artifacts/MixinBancorV3.json';
import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json';
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
@ -123,8 +120,10 @@ import * as MixinKyberDmm from '../test/generated-artifacts/MixinKyberDmm.json';
import * as MixinLido from '../test/generated-artifacts/MixinLido.json';
import * as MixinMakerPSM from '../test/generated-artifacts/MixinMakerPSM.json';
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
import * as MixinNerve from '../test/generated-artifacts/MixinNerve.json';
import * as MixinPlatypus from '../test/generated-artifacts/MixinPlatypus.json';
import * as MixinShell from '../test/generated-artifacts/MixinShell.json';
import * as MixinSolidly from '../test/generated-artifacts/MixinSolidly.json';
import * as MixinSynthetix from '../test/generated-artifacts/MixinSynthetix.json';
import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json';
@ -237,7 +236,6 @@ export const artifacts = {
FundRecoveryFeature: FundRecoveryFeature as ContractArtifact,
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact,
MetaTransactionsFeatureV2: MetaTransactionsFeatureV2 as ContractArtifact,
NativeOrdersFeature: NativeOrdersFeature as ContractArtifact,
OtcOrdersFeature: OtcOrdersFeature as ContractArtifact,
OwnableFeature: OwnableFeature as ContractArtifact,
@ -255,7 +253,6 @@ export const artifacts = {
IFundRecoveryFeature: IFundRecoveryFeature as ContractArtifact,
ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact,
IMetaTransactionsFeature: IMetaTransactionsFeature as ContractArtifact,
IMetaTransactionsFeatureV2: IMetaTransactionsFeatureV2 as ContractArtifact,
IMultiplexFeature: IMultiplexFeature as ContractArtifact,
INativeOrdersEvents: INativeOrdersEvents as ContractArtifact,
INativeOrdersFeature: INativeOrdersFeature as ContractArtifact,
@ -321,8 +318,6 @@ export const artifacts = {
ArbitrumBridgeAdapter: ArbitrumBridgeAdapter as ContractArtifact,
AvalancheBridgeAdapter: AvalancheBridgeAdapter as ContractArtifact,
BSCBridgeAdapter: BSCBridgeAdapter as ContractArtifact,
BaseBridgeAdapter: BaseBridgeAdapter as ContractArtifact,
BaseGoerliBridgeAdapter: BaseGoerliBridgeAdapter as ContractArtifact,
BridgeProtocols: BridgeProtocols as ContractArtifact,
CeloBridgeAdapter: CeloBridgeAdapter as ContractArtifact,
EthereumBridgeAdapter: EthereumBridgeAdapter as ContractArtifact,
@ -333,6 +328,7 @@ export const artifacts = {
MixinAaveV2: MixinAaveV2 as ContractArtifact,
MixinBalancer: MixinBalancer as ContractArtifact,
MixinBalancerV2Batch: MixinBalancerV2Batch as ContractArtifact,
MixinBancor: MixinBancor as ContractArtifact,
MixinBancorV3: MixinBancorV3 as ContractArtifact,
MixinCompound: MixinCompound as ContractArtifact,
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
@ -343,10 +339,12 @@ export const artifacts = {
MixinGMX: MixinGMX as ContractArtifact,
MixinKyberDmm: MixinKyberDmm as ContractArtifact,
MixinLido: MixinLido as ContractArtifact,
MixinMStable: MixinMStable as ContractArtifact,
MixinMakerPSM: MixinMakerPSM as ContractArtifact,
MixinMooniswap: MixinMooniswap as ContractArtifact,
MixinNerve: MixinNerve as ContractArtifact,
MixinPlatypus: MixinPlatypus as ContractArtifact,
MixinShell: MixinShell as ContractArtifact,
MixinSolidly: MixinSolidly as ContractArtifact,
MixinSynthetix: MixinSynthetix as ContractArtifact,
MixinUniswap: MixinUniswap as ContractArtifact,

View File

@ -8,8 +8,6 @@ export * from '../test/generated-wrappers/affiliate_fee_transformer';
export * from '../test/generated-wrappers/arbitrum_bridge_adapter';
export * from '../test/generated-wrappers/avalanche_bridge_adapter';
export * from '../test/generated-wrappers/b_s_c_bridge_adapter';
export * from '../test/generated-wrappers/base_bridge_adapter';
export * from '../test/generated-wrappers/base_goerli_bridge_adapter';
export * from '../test/generated-wrappers/batch_fill_native_orders_feature';
export * from '../test/generated-wrappers/bootstrap_feature';
export * from '../test/generated-wrappers/bridge_protocols';
@ -51,7 +49,6 @@ export * from '../test/generated-wrappers/i_liquidity_provider';
export * from '../test/generated-wrappers/i_liquidity_provider_feature';
export * from '../test/generated-wrappers/i_liquidity_provider_sandbox';
export * from '../test/generated-wrappers/i_meta_transactions_feature';
export * from '../test/generated-wrappers/i_meta_transactions_feature_v2';
export * from '../test/generated-wrappers/i_mooniswap_pool';
export * from '../test/generated-wrappers/i_multiplex_feature';
export * from '../test/generated-wrappers/i_native_orders_events';
@ -105,10 +102,10 @@ export * from '../test/generated-wrappers/liquidity_provider_feature';
export * from '../test/generated-wrappers/liquidity_provider_sandbox';
export * from '../test/generated-wrappers/log_metadata_transformer';
export * from '../test/generated-wrappers/meta_transactions_feature';
export * from '../test/generated-wrappers/meta_transactions_feature_v2';
export * from '../test/generated-wrappers/mixin_aave_v2';
export * from '../test/generated-wrappers/mixin_balancer';
export * from '../test/generated-wrappers/mixin_balancer_v2_batch';
export * from '../test/generated-wrappers/mixin_bancor';
export * from '../test/generated-wrappers/mixin_bancor_v3';
export * from '../test/generated-wrappers/mixin_compound';
export * from '../test/generated-wrappers/mixin_crypto_com';
@ -119,10 +116,12 @@ export * from '../test/generated-wrappers/mixin_dodo_v2';
export * from '../test/generated-wrappers/mixin_g_m_x';
export * from '../test/generated-wrappers/mixin_kyber_dmm';
export * from '../test/generated-wrappers/mixin_lido';
export * from '../test/generated-wrappers/mixin_m_stable';
export * from '../test/generated-wrappers/mixin_maker_p_s_m';
export * from '../test/generated-wrappers/mixin_mooniswap';
export * from '../test/generated-wrappers/mixin_nerve';
export * from '../test/generated-wrappers/mixin_platypus';
export * from '../test/generated-wrappers/mixin_shell';
export * from '../test/generated-wrappers/mixin_solidly';
export * from '../test/generated-wrappers/mixin_synthetix';
export * from '../test/generated-wrappers/mixin_uniswap';

View File

@ -263,7 +263,6 @@ contract MetaTransactionTest is LocalTest {
function test_transformERC20() external {
bytes memory transformCallData = _transformERC20Call(zrx, dai, USER_ADDRESS);
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(transformCallData);
LibSignature.Signature memory sig = _mtxSignature(mtxData);
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
vm.expectEmit(true, false, false, true);
@ -274,8 +273,10 @@ contract MetaTransactionTest is LocalTest {
address(this)
);
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(
mtxData,
_mtxSignature(mtxData)
);
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
assertEq(dai.balanceOf(USER_ADDRESS), 0);
assertEq(weth.balanceOf(address(this)), 1);
@ -284,7 +285,6 @@ contract MetaTransactionTest is LocalTest {
function test_rfqOrder() external {
bytes memory callData = _makeTestRfqOrder(zrx, dai, signerAddress, USER_ADDRESS, signerKey);
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(callData);
LibSignature.Signature memory sig = _mtxSignature(mtxData);
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
vm.expectEmit(true, false, false, true);
@ -295,7 +295,10 @@ contract MetaTransactionTest is LocalTest {
address(this)
);
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(
mtxData,
_mtxSignature(mtxData)
);
assertEq(zrx.balanceOf(signerAddress), 0);
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);
@ -307,7 +310,6 @@ contract MetaTransactionTest is LocalTest {
function test_fillLimitOrder() external {
bytes memory callData = _makeTestLimitOrder(zrx, dai, signerAddress, USER_ADDRESS, signerKey);
IMetaTransactionsFeatureV2.MetaTransactionDataV2 memory mtxData = _getMetaTransaction(callData);
LibSignature.Signature memory sig = _mtxSignature(mtxData);
assertEq(dai.balanceOf(USER_ADDRESS), 1e18);
vm.expectEmit(true, false, false, true);
@ -318,7 +320,10 @@ contract MetaTransactionTest is LocalTest {
address(this)
);
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(mtxData, sig);
IMetaTransactionsFeatureV2(address(zeroExDeployed.zeroEx)).executeMetaTransactionV2(
mtxData,
_mtxSignature(mtxData)
);
assertEq(zrx.balanceOf(signerAddress), 0);
assertEq(zrx.balanceOf(USER_ADDRESS), 1e18);

View File

@ -4,62 +4,48 @@
"UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x952ffc4c47d66b454a8181f5c68b6248e18b66ec",
"TraderJoeV2Quoter": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
"KyberElasticPool": "0x952ffc4c47d66b454a8181f5c68b6248e18b66ec"
},
"56": {
"UniswapV2Router": "0x10ed43c718714eb63d5aa57b78b54704e256024e",
"UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0xfbfab68ba077d099cd4b66fa76920572cc0b557c",
"TraderJoeV2Quoter": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
"KyberElasticPool": "0xfbfab68ba077d099cd4b66fa76920572cc0b557c"
},
"137": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506",
"UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0xf9cc934753a127100585812181ac04d07158a4c2",
"TraderJoeV2Quoter": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
"KyberElasticPool": "0xf9cc934753a127100585812181ac04d07158a4c2"
},
"43114": {
"UniswapV2Router": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10",
"UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x6038373de7f64da99b2a31951628b7d778b2c3cf",
"TraderJoeV2Quoter": "0x64b57F4249aA99a812212cee7DAEFEDC40B203cD",
"TraderJoeV2Router": "0xb4315e873dBcf96Ffd0acd8EA43f689D8c20fB30"
"KyberElasticPool": "0x6038373de7f64da99b2a31951628b7d778b2c3cf"
},
"250": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506",
"UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x8dcf5fed6ae6bf0befb5e4f0c9414c2cb9a4ed01",
"TraderJoeV2Quoter": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
"KyberElasticPool": "0x8dcf5fed6ae6bf0befb5e4f0c9414c2cb9a4ed01"
},
"10": {
"UniswapV2Router": "0x0000000000000000000000000000000000000000",
"UniswapV3Router": "0x61ffe014ba17989e743c5f6cb21bf9697530b21e",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x7e29ccaa4bf2894aca02c77e6b99cafc1d24b2f5",
"TraderJoeV2Quoter": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
"KyberElasticPool": "0x7e29ccaa4bf2894aca02c77e6b99cafc1d24b2f5"
},
"42161": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506",
"UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x087abaab9cd85025a8b3916948c69fe173c837ea",
"TraderJoeV2Quoter": "0x64b57F4249aA99a812212cee7DAEFEDC40B203cD",
"TraderJoeV2Router": "0xb4315e873dBcf96Ffd0acd8EA43f689D8c20fB30"
"KyberElasticPool": "0x087abaab9cd85025a8b3916948c69fe173c837ea"
}
}

View File

@ -20,8 +20,8 @@
"43114": {
"WrappedNativeToken": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
"DAI": "0xd586e7f844cea2f87f50152665bcbc2c279d8d70",
"USDC": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"USDT": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7"
"USDC": "0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664",
"USDT": "0xc7198437980c041c805A1EDcbA50c1Ce5db95118"
},
"250": {
"WrappedNativeToken": "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83",

View File

@ -38,8 +38,8 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
function test_swapERC20ForERC20OnKyberElastic() public {
for (uint256 i = 0; i < chains.length; i++) {
// kyberelastic mixin not added to fantom yet
if (i == 4) {
// kyberelastic mixin not deployed to these chains yet (bsc, fantom, optimism)
if (i == 1 || i == 4 || i == 5) {
continue;
}
vm.selectFork(forkIds[chains[i]]);
@ -54,76 +54,6 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
}
}
function test_swapERC20ForERC20OnTraderJoeV2() public {
for (uint256 i = 0; i < chains.length; i++) {
// TraderJoeV2 mixin only enabled on Avalanche and Arbitrum
if (i != 3 && i != 6) {
continue;
}
vm.selectFork(forkIds[chains[i]]);
labelAddresses(
chains[i],
indexChainsByChain[chains[i]],
getTokens(i),
getContractAddresses(i),
getLiquiditySourceAddresses(i)
);
swapOnTraderJoeV2(getTokens(i), getContractAddresses(i), getLiquiditySourceAddresses(i));
}
}
function swapOnTraderJoeV2(
TokenAddresses memory tokens,
ContractAddresses memory addresses,
LiquiditySources memory sources
) public onlyForked {
if (sources.TraderJoeV2Router == address(0)) {
emit log_string("TraderJoeV2Router not available on this chain");
return;
}
if (sources.TraderJoeV2Quoter == address(0)) {
emit log_string("TraderJoeV2Quoter not available on this chain");
return;
}
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
fqtData.sellToken = IERC20Token(address(tokens.USDC));
fqtData.buyToken = IERC20Token(address(tokens.USDT));
fqtData.fillSequence = new FillQuoteTransformer.OrderType[](1);
fqtData.fillSequence[0] = FillQuoteTransformer.OrderType.Bridge;
fqtData.fillAmount = 1e6;
(uint256 amountOut, uint256 binStep, uint256 version) = sampleTraderJoeV2(
fqtData.fillAmount,
address(fqtData.sellToken),
address(fqtData.buyToken),
sources.TraderJoeV2Quoter
);
log_named_uint("amountOut", amountOut);
IBridgeAdapter.BridgeOrder memory order;
{
address[] memory tokenPath = new address[](2);
tokenPath[0] = address(fqtData.sellToken);
tokenPath[1] = address(fqtData.buyToken);
uint256[] memory binSteps = new uint256[](1);
binSteps[0] = binStep;
uint256[] memory versions = new uint256[](1);
versions[0] = version;
order.bridgeData = abi.encode(address(sources.TraderJoeV2Router), tokenPath, binSteps, versions);
}
order.source = bytes32(uint256(BridgeProtocols.TRADERJOEV2) << 128);
order.takerTokenAmount = fqtData.fillAmount;
order.makerTokenAmount = amountOut;
fqtData.bridgeOrders = new IBridgeAdapter.BridgeOrder[](1);
fqtData.bridgeOrders[0] = order;
settleAndLogBalances(fqtData, tokens, addresses);
}
function swapOnKyberElastic(
TokenAddresses memory tokens,
ContractAddresses memory addresses,
@ -141,6 +71,20 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
emit log_string("KyberElasticPool not available on this chain");
return;
}
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
transformations[0].deploymentNonce = _findTransformerNonce(
address(addresses.transformers.wethTransformer),
address(addresses.exchangeProxyTransformerDeployer)
);
emit log_named_uint("WethTransformer nonce", transformations[0].deploymentNonce);
createNewFQT(tokens.WrappedNativeToken, addresses.exchangeProxy, addresses.exchangeProxyTransformerDeployer);
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
transformations[1].deploymentNonce = _findTransformerNonce(
address(fillQuoteTransformer),
address(addresses.exchangeProxyTransformerDeployer)
);
emit log_named_uint("FillQuoteTransformer nonce", transformations[1].deploymentNonce);
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
@ -167,8 +111,37 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
order.makerTokenAmount = amountOut;
order.bridgeData = abi.encode(address(sources.KyberElasticRouter), path);
fqtData.bridgeOrders[0] = order;
transformations[1].data = abi.encode(fqtData);
settleAndLogBalances(fqtData, tokens, addresses);
vm.deal(address(this), 1e18);
uint256 balanceETHBefore = address(this).balance;
uint256 balanceERC20Before = IERC20Token(tokens.USDT).balanceOf(address(this));
writeTokenBalance(address(this), address(tokens.USDC), 1e16);
uint256 balanceUSDCbefore = IERC20Token(tokens.USDC).balanceOf(address(this));
IERC20Token(address(tokens.USDC)).approve(addresses.exchangeProxy, 1e16);
IZeroEx(payable(addresses.exchangeProxy)).transformERC20{value: 1e18}(
// input token
IERC20Token(address(tokens.USDC)),
// output token
IERC20Token(address(tokens.USDT)),
// input token amount
1e6,
// min output token amount
order.makerTokenAmount,
// list of transform
transformations
);
log_named_uint("NativeAsset balance before", balanceETHBefore);
log_named_uint("ERC-20 balance before", balanceERC20Before);
log_named_uint("NativeAsset balance after", balanceETHBefore - address(this).balance);
log_named_uint("ERC-20 balance after", IERC20Token(tokens.USDT).balanceOf(address(this)) - balanceERC20Before);
log_named_uint("USDC balance before", balanceUSDCbefore);
log_named_uint("USDC balance after", IERC20Token(tokens.USDT).balanceOf(address(tokens.USDC)));
assert(IERC20Token(tokens.USDT).balanceOf(address(this)) > 0);
}
function sampleKyberElastic(
@ -177,7 +150,7 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
address makerToken,
address quoter,
address pool
) private returns (uint256 makerTokenAmount, bytes memory path) {
) public returns (uint256 makerTokenAmount, bytes memory path) {
log_string(" Sampling KyberElastic for tokens");
log_named_address(" ", takerToken);
log_string(" -> ");
@ -194,67 +167,4 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
(uint256 amountOut, , , ) = kyberQuoter.quoteExactInput(path, amount);
return (amountOut, path);
}
function sampleTraderJoeV2(
uint256 amount,
address takerToken,
address makerToken,
address quoter
) private returns (uint256 makerTokenAmount, uint256 binStep, uint256 version) {
log_string("Sampling TraderJoeV2");
log_named_address("takerToken", takerToken);
log_named_address("makerToken", makerToken);
log_named_address("quoter", quoter);
address[] memory tokenPath = new address[](2);
tokenPath[0] = takerToken;
tokenPath[1] = makerToken;
ITraderJoeV2Quoter.Quote memory quote = ITraderJoeV2Quoter(quoter).findBestPathFromAmountIn(
tokenPath,
uint128(amount)
);
return (quote.amounts[1], quote.binSteps[0], uint256(quote.versions[0]));
}
function deployFQTAndGetDeploymentNonce(
TokenAddresses memory tokens,
ContractAddresses memory addresses
) private returns (uint32) {
createNewFQT(tokens.WrappedNativeToken, addresses.exchangeProxy, addresses.exchangeProxyTransformerDeployer);
return
_findTransformerNonce(address(fillQuoteTransformer), address(addresses.exchangeProxyTransformerDeployer));
}
function settleAndLogBalances(
FillQuoteTransformer.TransformData memory fqtData,
TokenAddresses memory tokens,
ContractAddresses memory addresses
) private {
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
transformations[0].deploymentNonce = deployFQTAndGetDeploymentNonce(tokens, addresses);
transformations[0].data = abi.encode(fqtData);
address sellToken = address(fqtData.sellToken);
address buyToken = address(fqtData.buyToken);
writeTokenBalance(address(this), sellToken, 1e16);
uint256 sellTokenBalanceBefore = IERC20Token(sellToken).balanceOf(address(this));
uint256 buyTokenBalanceBefore = IERC20Token(buyToken).balanceOf(address(this));
IERC20Token(sellToken).approve(addresses.exchangeProxy, 1e16);
IZeroEx(payable(addresses.exchangeProxy)).transformERC20(
IERC20Token(sellToken),
IERC20Token(buyToken),
fqtData.fillAmount,
fqtData.bridgeOrders[0].makerTokenAmount,
transformations
);
log_named_uint("sellToken balance before", sellTokenBalanceBefore);
log_named_uint("sellToken balance after", IERC20Token(sellToken).balanceOf(address(this)));
log_named_uint("buyToken balance before", buyTokenBalanceBefore);
log_named_uint("buyToken balance after", IERC20Token(buyToken).balanceOf(address(this)));
}
}

View File

@ -33,7 +33,7 @@ contract SwapEthForERC20Test is Test, ForkUtils, TestUtils {
_setup();
}
function swapEthForERC20OnUniswap() public {
function test_swapEthForERC20OnUniswap() public {
log_string("SwapEthForERC20OnUniswap");
for (uint256 i = 0; i < chains.length; i++) {
//skip fantom/avax failing test

View File

@ -1,35 +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 "../../../contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol";
import "../../../contracts/src/transformers/bridges/BridgeProtocols.sol";
contract AvalancheBridgeAdapterTest is Test {
address constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;
AvalancheBridgeAdapter private adapter;
function setUp() public {
vm.chainId(43114);
adapter = new AvalancheBridgeAdapter(IEtherToken(WAVAX));
}
function testSupportsUniswapV3() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.UNISWAPV3) << 128)));
}
}

View File

@ -1,39 +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 "../../../contracts/src/transformers/bridges/BSCBridgeAdapter.sol";
import "../../../contracts/src/transformers/bridges/BridgeProtocols.sol";
contract BSCBridgeAdapterTest is Test {
address constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
BSCBridgeAdapter private adapter;
function setUp() public {
vm.chainId(56);
adapter = new BSCBridgeAdapter(IEtherToken(WBNB));
}
function testSupportsUniswapV3() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.UNISWAPV3) << 128)));
}
function testSupportMaverickV1() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.MAVERICKV1) << 128)));
}
}

View File

@ -1,47 +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 "../../../contracts/src/transformers/bridges/BaseBridgeAdapter.sol";
import "../../../contracts/src/transformers/bridges/BridgeProtocols.sol";
contract BaseBridgeAdapterTest is Test {
address constant WETH = 0x4200000000000000000000000000000000000006;
BaseBridgeAdapter private adapter;
function setUp() public {
vm.chainId(8453);
adapter = new BaseBridgeAdapter(IEtherToken(WETH));
}
function testSupportsUniswapV3() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.UNISWAPV3) << 128)));
}
function testSupportMaverickV1() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.MAVERICKV1) << 128)));
}
function testSupportSolidly() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.SOLIDLY) << 128)));
}
function testSupportVelodromeV2() public {
assertTrue(adapter.isSupportedSource(bytes32(uint256(BridgeProtocols.VELODROMEV2) << 128)));
}
}

Some files were not shown because too many files have changed in this diff Show More