Compare commits
48 Commits
protocol@e
...
@0x/protoc
Author | SHA1 | Date | |
---|---|---|---|
|
d9a16ed1f9 | ||
|
57a1120997 | ||
|
0945d4cef2 | ||
|
8f6f7ad453 | ||
|
bb4fad37fa | ||
|
d06daf2957 | ||
|
34314960ef | ||
|
832ba737ec | ||
|
6950fdbebb | ||
|
1849b1bb9a | ||
|
a883139220 | ||
|
bb2c26cb94 | ||
|
ba09a0b2bf | ||
|
b2d54f0238 | ||
|
4a3096495b | ||
|
23f6e9e53c | ||
|
d7dbc0576d | ||
|
15fb00e958 | ||
|
1d9295cc94 | ||
|
79f36cf6fb | ||
|
6ce4458a5d | ||
|
fad6e65c07 | ||
|
840c85373e | ||
|
0479bb5fe1 | ||
|
9ecc31ed54 | ||
|
eb29abd36c | ||
|
d202e01522 | ||
|
e838a6801b | ||
|
7439871aa0 | ||
|
317f2138c5 | ||
|
e5834f1901 | ||
|
5063446f93 | ||
|
0caf495a1a | ||
|
a20de0fc69 | ||
|
9aa0065d2d | ||
|
c24855e627 | ||
|
6bb72dd775 | ||
|
77d1ed257c | ||
|
5d265360c4 | ||
|
c9097f6e8b | ||
|
d3df985a42 | ||
|
7267420874 | ||
|
17e81432f1 | ||
|
57c767c3b1 | ||
|
dbb1c88ad9 | ||
|
254b850a8b | ||
|
e2242e5955 | ||
|
7a0255fee7 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -75,8 +75,9 @@ generated_docs/
|
||||
|
||||
TODO.md
|
||||
|
||||
# VSCode file
|
||||
# IDE file
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# generated contract artifacts/
|
||||
contracts/broker/generated-artifacts/
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "3.3.20",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631120757,
|
||||
"version": "3.3.19",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "3.3.18",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "3.3.17",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.3.20 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.19 - _September 8, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.18 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.3.17 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.20",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,18 +51,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.9",
|
||||
"@0x/contracts-utils": "^4.7.17",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/abi-gen": "^5.6.2",
|
||||
"@0x/contracts-gen": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.11",
|
||||
"@0x/contracts-utils": "^4.8.1",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "12.12.54",
|
||||
@@ -70,7 +70,7 @@
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
@@ -82,7 +82,7 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"ethers": "~4.0.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "5.4.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "5.4.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "5.4.9",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.4.11 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.10 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.4.9 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.4.9",
|
||||
"version": "5.4.11",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -34,7 +34,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/test-utils",
|
||||
"devDependencies": {
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
@@ -42,20 +42,20 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/assert": "^3.0.29",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/json-schemas": "^6.3.0",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-coverage": "^4.0.37",
|
||||
"@0x/sol-profiler": "^4.1.27",
|
||||
"@0x/sol-trace": "^3.0.37",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"@0x/sol-coverage": "^4.0.39",
|
||||
"@0x/sol-profiler": "^4.1.29",
|
||||
"@0x/sol-trace": "^3.0.39",
|
||||
"@0x/subproviders": "^6.6.0",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/js-combinatorics": "^0.5.29",
|
||||
"@types/lodash": "4.14.104",
|
||||
@@ -67,7 +67,7 @@
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"decimal.js": "^10.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"ethers": "~4.0.4",
|
||||
"js-combinatorics": "^0.5.3",
|
||||
|
@@ -1,4 +1,49 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1633374058,
|
||||
"version": "1.4.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1632957537,
|
||||
"version": "1.4.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Support cast vote by signature in Treasury"
|
||||
}
|
||||
],
|
||||
"timestamp": 1631710679
|
||||
},
|
||||
{
|
||||
"timestamp": 1631120757,
|
||||
"version": "1.3.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "1.3.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "1.3.3",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.4.2 - _October 4, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.1 - _September 29, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.0 - _September 15, 2021_
|
||||
|
||||
* Support cast vote by signature in Treasury
|
||||
|
||||
## v1.3.5 - _September 8, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.4 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.3 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -136,8 +136,9 @@ interface IZrxTreasury {
|
||||
returns (uint256 proposalId);
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
/// during the voting period for that proposal. See
|
||||
/// `getVotingPower` for how voting power is computed.
|
||||
/// 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
|
||||
@@ -150,6 +151,28 @@ interface IZrxTreasury {
|
||||
)
|
||||
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.
|
||||
|
@@ -34,11 +34,25 @@ contract ZrxTreasury is
|
||||
using LibRichErrorsV06 for bytes;
|
||||
using LibBytesV06 for bytes;
|
||||
|
||||
/// Contract name
|
||||
string private constant CONTRACT_NAME = "Zrx Treasury";
|
||||
|
||||
/// Contract version
|
||||
string private constant CONTRACT_VERSION = "1.0.0";
|
||||
|
||||
/// The EIP-712 typehash for the contract's domain
|
||||
bytes32 private constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
|
||||
|
||||
/// The EIP-712 typehash for the vote struct
|
||||
bytes32 private constant VOTE_TYPEHASH = keccak256("TreasuryVote(uint256 proposalId,bool support,bytes32[] operatedPoolIds)");
|
||||
|
||||
// Immutables
|
||||
IStaking public immutable override stakingProxy;
|
||||
DefaultPoolOperator public immutable override defaultPoolOperator;
|
||||
bytes32 public immutable override defaultPoolId;
|
||||
uint256 public immutable override votingPeriod;
|
||||
bytes32 immutable domainSeparator;
|
||||
|
||||
uint256 public override proposalThreshold;
|
||||
uint256 public override quorumThreshold;
|
||||
|
||||
@@ -67,6 +81,15 @@ contract ZrxTreasury is
|
||||
defaultPoolId = params.defaultPoolId;
|
||||
IStaking.Pool memory defaultPool = stakingProxy_.getStakingPool(params.defaultPoolId);
|
||||
defaultPoolOperator = DefaultPoolOperator(defaultPool.operator);
|
||||
domainSeparator = keccak256(
|
||||
abi.encode(
|
||||
DOMAIN_TYPEHASH,
|
||||
keccak256(bytes(CONTRACT_NAME)),
|
||||
_getChainId(),
|
||||
keccak256(bytes(CONTRACT_VERSION)),
|
||||
address(this)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// solhint-disable
|
||||
@@ -105,7 +128,7 @@ contract ZrxTreasury is
|
||||
/// 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
|
||||
/// @param operatedPoolIds The pools operated by the signer. The
|
||||
/// ZRX currently delegated to those pools will be accounted
|
||||
/// for in the voting power.
|
||||
/// @return proposalId The ID of the newly created proposal.
|
||||
@@ -150,8 +173,9 @@ contract ZrxTreasury is
|
||||
}
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
/// during the voting period for that proposal. See
|
||||
/// `getVotingPower` for how voting power is computed.
|
||||
/// 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
|
||||
@@ -165,43 +189,39 @@ contract ZrxTreasury is
|
||||
public
|
||||
override
|
||||
{
|
||||
if (proposalId >= proposalCount()) {
|
||||
revert("castVote/INVALID_PROPOSAL_ID");
|
||||
}
|
||||
if (hasVoted[proposalId][msg.sender]) {
|
||||
revert("castVote/ALREADY_VOTED");
|
||||
}
|
||||
return _castVote(msg.sender, proposalId, support, operatedPoolIds);
|
||||
}
|
||||
|
||||
Proposal memory proposal = proposals[proposalId];
|
||||
if (
|
||||
proposal.voteEpoch != stakingProxy.currentEpoch() ||
|
||||
_hasVoteEnded(proposal.voteEpoch)
|
||||
) {
|
||||
revert("castVote/VOTING_IS_CLOSED");
|
||||
}
|
||||
|
||||
uint256 votingPower = getVotingPower(msg.sender, operatedPoolIds);
|
||||
if (votingPower == 0) {
|
||||
revert("castVote/NO_VOTING_POWER");
|
||||
}
|
||||
|
||||
if (support) {
|
||||
proposals[proposalId].votesFor = proposals[proposalId].votesFor
|
||||
.safeAdd(votingPower);
|
||||
hasVoted[proposalId][msg.sender] = true;
|
||||
} else {
|
||||
proposals[proposalId].votesAgainst = proposals[proposalId].votesAgainst
|
||||
.safeAdd(votingPower);
|
||||
hasVoted[proposalId][msg.sender] = true;
|
||||
}
|
||||
|
||||
emit VoteCast(
|
||||
msg.sender,
|
||||
operatedPoolIds,
|
||||
proposalId,
|
||||
support,
|
||||
votingPower
|
||||
/// @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 voter. 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
|
||||
)
|
||||
public
|
||||
override
|
||||
{
|
||||
bytes32 structHash = keccak256(
|
||||
abi.encode(VOTE_TYPEHASH, proposalId, support, keccak256(abi.encodePacked(operatedPoolIds)))
|
||||
);
|
||||
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
|
||||
address signatory = ecrecover(digest, v, r, s);
|
||||
|
||||
return _castVote(signatory, proposalId, support, operatedPoolIds);
|
||||
}
|
||||
|
||||
/// @dev Executes a proposal that has passed and is
|
||||
@@ -373,4 +393,60 @@ contract ZrxTreasury is
|
||||
.safeAdd(votingPeriod);
|
||||
return block.timestamp > voteEndTime;
|
||||
}
|
||||
|
||||
/// @dev Casts a vote for the given proposal. Only callable
|
||||
/// during the voting period for that proposal. See
|
||||
/// `getVotingPower` for how voting power is computed.
|
||||
function _castVote(
|
||||
address voter,
|
||||
uint256 proposalId,
|
||||
bool support,
|
||||
bytes32[] memory operatedPoolIds
|
||||
)
|
||||
private
|
||||
{
|
||||
if (proposalId >= proposalCount()) {
|
||||
revert("_castVote/INVALID_PROPOSAL_ID");
|
||||
}
|
||||
if (hasVoted[proposalId][voter]) {
|
||||
revert("_castVote/ALREADY_VOTED");
|
||||
}
|
||||
|
||||
Proposal memory proposal = proposals[proposalId];
|
||||
if (
|
||||
proposal.voteEpoch != stakingProxy.currentEpoch() ||
|
||||
_hasVoteEnded(proposal.voteEpoch)
|
||||
) {
|
||||
revert("_castVote/VOTING_IS_CLOSED");
|
||||
}
|
||||
|
||||
uint256 votingPower = getVotingPower(voter, operatedPoolIds);
|
||||
if (votingPower == 0) {
|
||||
revert("_castVote/NO_VOTING_POWER");
|
||||
}
|
||||
|
||||
if (support) {
|
||||
proposals[proposalId].votesFor = proposals[proposalId].votesFor
|
||||
.safeAdd(votingPower);
|
||||
} else {
|
||||
proposals[proposalId].votesAgainst = proposals[proposalId].votesAgainst
|
||||
.safeAdd(votingPower);
|
||||
}
|
||||
hasVoted[proposalId][voter] = true;
|
||||
|
||||
emit VoteCast(
|
||||
voter,
|
||||
operatedPoolIds,
|
||||
proposalId,
|
||||
support,
|
||||
votingPower
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Gets the Ethereum chain id
|
||||
function _getChainId() private pure returns (uint256) {
|
||||
uint256 chainId;
|
||||
assembly { chainId := chainid() }
|
||||
return chainId;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-treasury",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -46,14 +46,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/abi-gen": "^5.6.2",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-erc20": "^3.3.17",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-erc20": "^3.3.20",
|
||||
"@0x/contracts-gen": "^2.0.40",
|
||||
"@0x/contracts-staking": "^2.0.45",
|
||||
"@0x/contracts-test-utils": "^5.4.9",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/contracts-test-utils": "^5.4.11",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
@@ -72,14 +72,14 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/protocol-utils": "^1.8.3",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/protocol-utils": "^1.9.2",
|
||||
"@0x/subproviders": "^6.6.0",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereumjs-util": "^7.0.10"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -17,8 +17,9 @@ import {
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
import { TreasuryVote } from '@0x/protocol-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { DefaultPoolOperatorContract, ZrxTreasuryContract, ZrxTreasuryEvents } from './wrappers';
|
||||
@@ -55,6 +56,8 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
let nonDefaultPoolId: string;
|
||||
let poolOperator: string;
|
||||
let delegator: string;
|
||||
let relayer: string;
|
||||
let delegatorPrivateKey: string;
|
||||
let actions: ProposedAction[];
|
||||
|
||||
async function deployStakingAsync(): Promise<void> {
|
||||
@@ -105,7 +108,10 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
[admin, poolOperator, delegator] = await env.getAccountAddressesAsync();
|
||||
const accounts = await env.getAccountAddressesAsync();
|
||||
[admin, poolOperator, delegator, relayer] = accounts;
|
||||
delegatorPrivateKey = hexUtils.toHex(constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(delegator)]);
|
||||
|
||||
zrx = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
erc20Artifacts.DummyERC20Token,
|
||||
env.provider,
|
||||
@@ -399,7 +405,7 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
expect(await treasury.proposalCount().callAsync()).to.bignumber.equal(1);
|
||||
});
|
||||
});
|
||||
describe('castVote()', () => {
|
||||
describe('castVote() and castVoteBySignature()', () => {
|
||||
const VOTE_PROPOSAL_ID = new BigNumber(0);
|
||||
const DELEGATOR_VOTING_POWER = new BigNumber(420);
|
||||
|
||||
@@ -418,17 +424,18 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
.propose(actions, currentEpoch.plus(2), PROPOSAL_DESCRIPTION, [])
|
||||
.awaitTransactionSuccessAsync({ from: delegator });
|
||||
});
|
||||
// castVote()
|
||||
it('Cannot vote on invalid proposalId', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
const tx = treasury
|
||||
.castVote(INVALID_PROPOSAL_ID, true, [])
|
||||
.awaitTransactionSuccessAsync({ from: delegator });
|
||||
return expect(tx).to.revertWith('castVote/INVALID_PROPOSAL_ID');
|
||||
return expect(tx).to.revertWith('_castVote/INVALID_PROPOSAL_ID');
|
||||
});
|
||||
it('Cannot vote before voting period starts', async () => {
|
||||
const tx = treasury.castVote(VOTE_PROPOSAL_ID, true, []).awaitTransactionSuccessAsync({ from: delegator });
|
||||
return expect(tx).to.revertWith('castVote/VOTING_IS_CLOSED');
|
||||
return expect(tx).to.revertWith('_castVote/VOTING_IS_CLOSED');
|
||||
});
|
||||
it('Cannot vote after voting period ends', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
@@ -436,14 +443,14 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
await env.web3Wrapper.increaseTimeAsync(TREASURY_PARAMS.votingPeriod.plus(1).toNumber());
|
||||
await env.web3Wrapper.mineBlockAsync();
|
||||
const tx = treasury.castVote(VOTE_PROPOSAL_ID, true, []).awaitTransactionSuccessAsync({ from: delegator });
|
||||
return expect(tx).to.revertWith('castVote/VOTING_IS_CLOSED');
|
||||
return expect(tx).to.revertWith('_castVote/VOTING_IS_CLOSED');
|
||||
});
|
||||
it('Cannot vote twice on same proposal', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
await treasury.castVote(VOTE_PROPOSAL_ID, true, []).awaitTransactionSuccessAsync({ from: delegator });
|
||||
const tx = treasury.castVote(VOTE_PROPOSAL_ID, false, []).awaitTransactionSuccessAsync({ from: delegator });
|
||||
return expect(tx).to.revertWith('castVote/ALREADY_VOTED');
|
||||
return expect(tx).to.revertWith('_castVote/ALREADY_VOTED');
|
||||
});
|
||||
it('Can cast a valid vote', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
@@ -465,6 +472,109 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
ZrxTreasuryEvents.VoteCast,
|
||||
);
|
||||
});
|
||||
// castVoteBySignature()
|
||||
it('Cannot vote by signature on invalid proposalId', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
const vote = new TreasuryVote({
|
||||
proposalId: INVALID_PROPOSAL_ID,
|
||||
verifyingContract: admin,
|
||||
});
|
||||
const signature = vote.getSignatureWithKey(delegatorPrivateKey);
|
||||
const tx = treasury
|
||||
.castVoteBySignature(INVALID_PROPOSAL_ID, true, [], signature.v, signature.r, signature.s)
|
||||
.awaitTransactionSuccessAsync({ from: relayer });
|
||||
return expect(tx).to.revertWith('_castVote/INVALID_PROPOSAL_ID');
|
||||
});
|
||||
it('Cannot vote by signature before voting period starts', async () => {
|
||||
const vote = new TreasuryVote({
|
||||
proposalId: VOTE_PROPOSAL_ID,
|
||||
verifyingContract: admin,
|
||||
});
|
||||
const signature = vote.getSignatureWithKey(delegatorPrivateKey);
|
||||
const tx = treasury
|
||||
.castVoteBySignature(VOTE_PROPOSAL_ID, true, [], signature.v, signature.r, signature.s)
|
||||
.awaitTransactionSuccessAsync({ from: relayer });
|
||||
return expect(tx).to.revertWith('_castVote/VOTING_IS_CLOSED');
|
||||
});
|
||||
it('Cannot vote by signature after voting period ends', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
await env.web3Wrapper.increaseTimeAsync(TREASURY_PARAMS.votingPeriod.plus(1).toNumber());
|
||||
await env.web3Wrapper.mineBlockAsync();
|
||||
|
||||
const vote = new TreasuryVote({
|
||||
proposalId: VOTE_PROPOSAL_ID,
|
||||
verifyingContract: admin,
|
||||
});
|
||||
const signature = vote.getSignatureWithKey(delegatorPrivateKey);
|
||||
const tx = treasury
|
||||
.castVoteBySignature(VOTE_PROPOSAL_ID, true, [], signature.v, signature.r, signature.s)
|
||||
.awaitTransactionSuccessAsync({ from: relayer });
|
||||
return expect(tx).to.revertWith('_castVote/VOTING_IS_CLOSED');
|
||||
});
|
||||
it('Can recover the address from signature correctly', async () => {
|
||||
const vote = new TreasuryVote({
|
||||
proposalId: VOTE_PROPOSAL_ID,
|
||||
verifyingContract: admin,
|
||||
});
|
||||
const signature = vote.getSignatureWithKey(delegatorPrivateKey);
|
||||
const publicKey = ethUtil.ecrecover(
|
||||
ethUtil.toBuffer(vote.getEIP712Hash()),
|
||||
signature.v,
|
||||
ethUtil.toBuffer(signature.r),
|
||||
ethUtil.toBuffer(signature.s),
|
||||
);
|
||||
const address = ethUtil.publicToAddress(publicKey);
|
||||
|
||||
expect(ethUtil.bufferToHex(address)).to.be.equal(delegator);
|
||||
});
|
||||
it('Can cast a valid vote by signature', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
|
||||
const vote = new TreasuryVote({
|
||||
proposalId: VOTE_PROPOSAL_ID,
|
||||
verifyingContract: treasury.address,
|
||||
chainId: 1337,
|
||||
support: false,
|
||||
});
|
||||
const signature = vote.getSignatureWithKey(delegatorPrivateKey);
|
||||
const tx = await treasury
|
||||
.castVoteBySignature(VOTE_PROPOSAL_ID, false, [], signature.v, signature.r, signature.s)
|
||||
.awaitTransactionSuccessAsync({ from: relayer });
|
||||
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
voter: delegator,
|
||||
operatedPoolIds: [],
|
||||
proposalId: VOTE_PROPOSAL_ID,
|
||||
support: vote.support,
|
||||
votingPower: DELEGATOR_VOTING_POWER,
|
||||
},
|
||||
],
|
||||
ZrxTreasuryEvents.VoteCast,
|
||||
);
|
||||
});
|
||||
it('Cannot vote by signature twice on same proposal', async () => {
|
||||
await fastForwardToNextEpochAsync();
|
||||
await fastForwardToNextEpochAsync();
|
||||
await treasury.castVote(VOTE_PROPOSAL_ID, true, []).awaitTransactionSuccessAsync({ from: delegator });
|
||||
|
||||
const secondVote = new TreasuryVote({
|
||||
proposalId: VOTE_PROPOSAL_ID,
|
||||
verifyingContract: treasury.address,
|
||||
chainId: 1337,
|
||||
support: false,
|
||||
});
|
||||
const signature = secondVote.getSignatureWithKey(delegatorPrivateKey);
|
||||
const secondVoteTx = treasury
|
||||
.castVoteBySignature(VOTE_PROPOSAL_ID, false, [], signature.v, signature.r, signature.s)
|
||||
.awaitTransactionSuccessAsync({ from: relayer });
|
||||
return expect(secondVoteTx).to.revertWith('_castVote/ALREADY_VOTED');
|
||||
});
|
||||
});
|
||||
describe('execute()', () => {
|
||||
let passedProposalId: BigNumber;
|
||||
@@ -473,7 +583,7 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
let ongoingVoteProposalId: BigNumber;
|
||||
|
||||
before(async () => {
|
||||
// OPerator has enough ZRX to create and pass a proposal
|
||||
// Operator has enough ZRX to create and pass a proposal
|
||||
await staking.stake(TREASURY_PARAMS.quorumThreshold).awaitTransactionSuccessAsync({ from: poolOperator });
|
||||
await staking
|
||||
.moveStake(
|
||||
@@ -549,7 +659,7 @@ blockchainTests.resets('Treasury governance', env => {
|
||||
});
|
||||
it('Cannot execute before or after the execution epoch', async () => {
|
||||
const tooEarly = treasury.execute(passedProposalId, actions).awaitTransactionSuccessAsync();
|
||||
expect(tooEarly).to.revertWith('_assertProposalExecutable/CANNOT_EXECUTE_THIS_EPOCH');
|
||||
await expect(tooEarly).to.revertWith('_assertProposalExecutable/CANNOT_EXECUTE_THIS_EPOCH');
|
||||
await fastForwardToNextEpochAsync();
|
||||
// Proposal 0 is executable here
|
||||
await fastForwardToNextEpochAsync();
|
||||
|
@@ -1,4 +1,32 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "4.8.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.8.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added FundRecoveryFeature to the 0x EP",
|
||||
"pr": 306
|
||||
}
|
||||
],
|
||||
"timestamp": 1631120757
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "4.7.18",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "4.7.17",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.8.1 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.8.0 - _September 8, 2021_
|
||||
|
||||
* Added FundRecoveryFeature to the 0x EP (#306)
|
||||
|
||||
## v4.7.18 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.7.17 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.7.17",
|
||||
"version": "4.8.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,15 +50,15 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/utils",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.9",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/abi-gen": "^5.6.2",
|
||||
"@0x/contracts-gen": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.11",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -79,11 +79,11 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereum-types": "^3.5.0"
|
||||
"ethereum-types": "^3.6.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,50 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1633374058,
|
||||
"version": "0.29.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.29.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Export TransformERC20FeatureContract",
|
||||
"pr": 282
|
||||
}
|
||||
],
|
||||
"timestamp": 1632957537
|
||||
},
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "0.28.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631120757,
|
||||
"version": "0.28.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "0.28.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.28.2",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.29.1 - _October 4, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.29.0 - _September 29, 2021_
|
||||
|
||||
* Export TransformERC20FeatureContract (#282)
|
||||
|
||||
## v0.28.5 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.28.4 - _September 8, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.28.3 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.28.2 - _August 19, 2021_
|
||||
|
||||
* Add ethers as an explicit dependency (#310)
|
||||
|
@@ -33,6 +33,7 @@ import "./features/interfaces/INativeOrdersFeature.sol";
|
||||
import "./features/interfaces/IBatchFillNativeOrdersFeature.sol";
|
||||
import "./features/interfaces/IMultiplexFeature.sol";
|
||||
import "./features/interfaces/IOtcOrdersFeature.sol";
|
||||
import "./features/interfaces/IFundRecoveryFeature.sol";
|
||||
|
||||
|
||||
/// @dev Interface for a fully featured Exchange Proxy.
|
||||
@@ -48,7 +49,8 @@ interface IZeroEx is
|
||||
INativeOrdersFeature,
|
||||
IBatchFillNativeOrdersFeature,
|
||||
IMultiplexFeature,
|
||||
IOtcOrdersFeature
|
||||
IOtcOrdersFeature,
|
||||
IFundRecoveryFeature
|
||||
{
|
||||
// solhint-disable state-visibility
|
||||
|
||||
|
@@ -0,0 +1,66 @@
|
||||
// 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.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "../migrations/LibMigrate.sol";
|
||||
import "../fixins/FixinCommon.sol";
|
||||
import "./interfaces/IFeature.sol";
|
||||
import "./interfaces/IFundRecoveryFeature.sol";
|
||||
import "../transformers/LibERC20Transformer.sol";
|
||||
|
||||
contract FundRecoveryFeature is
|
||||
IFeature,
|
||||
IFundRecoveryFeature,
|
||||
FixinCommon
|
||||
{
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "FundRecoveryFeature";
|
||||
/// @dev Version of this feature.
|
||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
|
||||
|
||||
/// @dev Initialize and register this feature.
|
||||
/// Should be delegatecalled by `Migrate.migrate()`.
|
||||
/// @return success `LibMigrate.SUCCESS` on success.
|
||||
function migrate()
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
_registerFeatureFunction(this.transferTrappedTokensTo.selector);
|
||||
return LibMigrate.MIGRATE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Recovers ERC20 tokens or ETH from the 0x Exchange Proxy contract
|
||||
/// @param erc20 ERC20 Token Address. (You can also pass in `0xeeeee...` to indicate ETH)
|
||||
/// @param amountOut Amount of tokens to withdraw.
|
||||
/// @param recipientWallet Recipient wallet address.
|
||||
function transferTrappedTokensTo(
|
||||
IERC20TokenV06 erc20,
|
||||
uint256 amountOut,
|
||||
address payable recipientWallet
|
||||
)
|
||||
external
|
||||
override
|
||||
onlyOwner
|
||||
{
|
||||
if(amountOut == uint256(-1)) {
|
||||
amountOut = LibERC20Transformer.getTokenBalanceOf(erc20, address(this));
|
||||
}
|
||||
LibERC20Transformer.transformerTransfer(erc20, recipientWallet, amountOut);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
|
||||
|
||||
/// @dev Exchange Proxy Recovery Functions
|
||||
interface IFundRecoveryFeature {
|
||||
|
||||
/// @dev calledFrom FundRecoveryFeature.transferTrappedTokensTo() This will be delegatecalled
|
||||
/// in the context of the Exchange Proxy instance being used.
|
||||
/// @param erc20 ERC20 Token Address.
|
||||
/// @param amountOut Amount of tokens to withdraw.
|
||||
/// @param recipientWallet Recipient wallet address.
|
||||
function transferTrappedTokensTo(
|
||||
IERC20TokenV06 erc20,
|
||||
uint256 amountOut,
|
||||
address payable recipientWallet
|
||||
)
|
||||
external;
|
||||
}
|
@@ -25,7 +25,6 @@ import "./BridgeProtocols.sol";
|
||||
import "./mixins/MixinBalancer.sol";
|
||||
import "./mixins/MixinBalancerV2.sol";
|
||||
import "./mixins/MixinBancor.sol";
|
||||
import "./mixins/MixinClipper.sol";
|
||||
import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCurveV2.sol";
|
||||
@@ -51,7 +50,6 @@ contract BridgeAdapter is
|
||||
MixinBalancer,
|
||||
MixinBalancerV2,
|
||||
MixinBancor,
|
||||
MixinClipper,
|
||||
MixinCoFiX,
|
||||
MixinCurve,
|
||||
MixinCurveV2,
|
||||
@@ -77,7 +75,6 @@ contract BridgeAdapter is
|
||||
MixinBalancer()
|
||||
MixinBalancerV2()
|
||||
MixinBancor(weth)
|
||||
MixinClipper(weth)
|
||||
MixinCoFiX()
|
||||
MixinCurve(weth)
|
||||
MixinCurveV2()
|
||||
@@ -248,13 +245,6 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (protocolId == BridgeProtocols.CLIPPER) {
|
||||
boughtAmount = _tradeClipper(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
sellToken,
|
||||
|
@@ -49,5 +49,5 @@ library BridgeProtocols {
|
||||
uint128 internal constant KYBERDMM = 19;
|
||||
uint128 internal constant CURVEV2 = 20;
|
||||
uint128 internal constant LIDO = 21;
|
||||
uint128 internal constant CLIPPER = 22;
|
||||
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
|
||||
}
|
||||
|
@@ -1,148 +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.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "../IBridgeAdapter.sol";
|
||||
import "../../../vendor/ILiquidityProvider.sol";
|
||||
|
||||
contract MixinClipper {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
|
||||
constructor(IEtherTokenV06 weth)
|
||||
public
|
||||
{
|
||||
WETH = weth;
|
||||
}
|
||||
|
||||
function _tradeClipper(
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// We can only use ETH with Clipper, no WETH available
|
||||
(ILiquidityProvider clipper, bytes memory auxiliaryData) =
|
||||
abi.decode(bridgeData, (ILiquidityProvider, bytes));
|
||||
|
||||
if (sellToken == WETH) {
|
||||
boughtAmount = _executeSellEthForToken(
|
||||
clipper,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
} else if (buyToken == WETH) {
|
||||
boughtAmount = _executeSellTokenForEth(
|
||||
clipper,
|
||||
sellToken,
|
||||
sellAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _executeSellTokenForToken(
|
||||
clipper,
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
|
||||
function _executeSellEthForToken(
|
||||
ILiquidityProvider clipper,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory auxiliaryData
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Clipper requires ETH and doesn't support WETH
|
||||
WETH.withdraw(sellAmount);
|
||||
boughtAmount = clipper.sellEthForToken{ value: sellAmount }(
|
||||
buyToken,
|
||||
address(this),
|
||||
1,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
|
||||
function _executeSellTokenForEth(
|
||||
ILiquidityProvider clipper,
|
||||
IERC20TokenV06 sellToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory auxiliaryData
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Optimization: We can transfer the tokens into clipper rather than
|
||||
// have an allowance updated
|
||||
sellToken.compatTransfer(address(clipper), sellAmount);
|
||||
|
||||
boughtAmount = clipper.sellTokenForEth(
|
||||
sellToken,
|
||||
payable(address(this)),
|
||||
1,
|
||||
auxiliaryData
|
||||
);
|
||||
|
||||
// we want WETH for possible future trades
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
}
|
||||
|
||||
function _executeSellTokenForToken(
|
||||
ILiquidityProvider clipper,
|
||||
IERC20TokenV06 sellToken,
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory auxiliaryData
|
||||
)
|
||||
private
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Optimization: We can transfer the tokens into clipper rather than
|
||||
// have an allowance updated
|
||||
sellToken.compatTransfer(address(clipper), sellAmount);
|
||||
|
||||
boughtAmount = clipper.sellTokenForToken(
|
||||
sellToken,
|
||||
buyToken,
|
||||
address(this),
|
||||
1,
|
||||
auxiliaryData
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-zero-ex",
|
||||
"version": "0.28.2",
|
||||
"version": "0.29.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,7 +43,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinClipper|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -55,14 +55,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/contracts-erc20": "^3.3.17",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.9",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/abi-gen": "^5.6.2",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/contracts-erc20": "^3.3.20",
|
||||
"@0x/contracts-gen": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.11",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/order-utils": "^10.4.28",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
@@ -82,14 +82,14 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/protocol-utils": "^1.8.3",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/protocol-utils": "^1.9.2",
|
||||
"@0x/subproviders": "^6.6.0",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"ethers": "~4.0.4"
|
||||
},
|
||||
|
@@ -47,6 +47,7 @@ export {
|
||||
MultiplexFeatureContract,
|
||||
PayTakerTransformerContract,
|
||||
PositiveSlippageFeeTransformerContract,
|
||||
TransformERC20FeatureContract,
|
||||
WethTransformerContract,
|
||||
ZeroExContract,
|
||||
} from './wrappers';
|
||||
|
@@ -21,6 +21,7 @@ import * as FixinReentrancyGuard from '../test/generated-artifacts/FixinReentran
|
||||
import * as FixinTokenSpender from '../test/generated-artifacts/FixinTokenSpender.json';
|
||||
import * as FlashWallet from '../test/generated-artifacts/FlashWallet.json';
|
||||
import * as FullMigration from '../test/generated-artifacts/FullMigration.json';
|
||||
import * as FundRecoveryFeature from '../test/generated-artifacts/FundRecoveryFeature.json';
|
||||
import * as IBatchFillNativeOrdersFeature from '../test/generated-artifacts/IBatchFillNativeOrdersFeature.json';
|
||||
import * as IBootstrapFeature from '../test/generated-artifacts/IBootstrapFeature.json';
|
||||
import * as IBridgeAdapter from '../test/generated-artifacts/IBridgeAdapter.json';
|
||||
@@ -28,6 +29,7 @@ import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
|
||||
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
|
||||
import * as IFeature from '../test/generated-artifacts/IFeature.json';
|
||||
import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json';
|
||||
import * as IFundRecoveryFeature from '../test/generated-artifacts/IFundRecoveryFeature.json';
|
||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||
import * as ILiquidityProviderFeature from '../test/generated-artifacts/ILiquidityProviderFeature.json';
|
||||
import * as ILiquidityProviderSandbox from '../test/generated-artifacts/ILiquidityProviderSandbox.json';
|
||||
@@ -82,7 +84,6 @@ import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransa
|
||||
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
||||
import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json';
|
||||
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
|
||||
import * as MixinClipper from '../test/generated-artifacts/MixinClipper.json';
|
||||
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
||||
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
@@ -198,6 +199,7 @@ export const artifacts = {
|
||||
TransformerDeployer: TransformerDeployer as ContractArtifact,
|
||||
BatchFillNativeOrdersFeature: BatchFillNativeOrdersFeature as ContractArtifact,
|
||||
BootstrapFeature: BootstrapFeature as ContractArtifact,
|
||||
FundRecoveryFeature: FundRecoveryFeature as ContractArtifact,
|
||||
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
|
||||
MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact,
|
||||
NativeOrdersFeature: NativeOrdersFeature as ContractArtifact,
|
||||
@@ -211,6 +213,7 @@ export const artifacts = {
|
||||
IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact,
|
||||
IBootstrapFeature: IBootstrapFeature as ContractArtifact,
|
||||
IFeature: IFeature as ContractArtifact,
|
||||
IFundRecoveryFeature: IFundRecoveryFeature as ContractArtifact,
|
||||
ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact,
|
||||
IMetaTransactionsFeature: IMetaTransactionsFeature as ContractArtifact,
|
||||
IMultiplexFeature: IMultiplexFeature as ContractArtifact,
|
||||
@@ -272,7 +275,6 @@ export const artifacts = {
|
||||
MixinBalancer: MixinBalancer as ContractArtifact,
|
||||
MixinBalancerV2: MixinBalancerV2 as ContractArtifact,
|
||||
MixinBancor: MixinBancor as ContractArtifact,
|
||||
MixinClipper: MixinClipper as ContractArtifact,
|
||||
MixinCoFiX: MixinCoFiX as ContractArtifact,
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
|
96
contracts/zero-ex/test/features/fund_recovery_tests.ts
Normal file
96
contracts/zero-ex/test/features/fund_recovery_tests.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, OwnableRevertErrors } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
|
||||
import { IOwnableFeatureContract, IZeroExContract } from '../../src/wrappers';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { FundRecoveryFeatureContract } from '../generated-wrappers/fund_recovery_feature';
|
||||
import { abis } from '../utils/abis';
|
||||
import { fullMigrateAsync } from '../utils/migration';
|
||||
import { TestMintableERC20TokenContract } from '../wrappers';
|
||||
|
||||
blockchainTests('FundRecovery', async env => {
|
||||
let owner: string;
|
||||
let zeroEx: IZeroExContract;
|
||||
let token: TestMintableERC20TokenContract;
|
||||
before(async () => {
|
||||
const INITIAL_ERC20_BALANCE = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18);
|
||||
[owner] = await env.getAccountAddressesAsync();
|
||||
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {});
|
||||
token = await TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestMintableERC20Token,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
await token.mint(zeroEx.address, INITIAL_ERC20_BALANCE).awaitTransactionSuccessAsync();
|
||||
const featureImpl = await FundRecoveryFeatureContract.deployFrom0xArtifactAsync(
|
||||
artifacts.FundRecoveryFeature,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis)
|
||||
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
|
||||
.awaitTransactionSuccessAsync({ from: owner });
|
||||
});
|
||||
blockchainTests.resets('Should delegatecall `transferTrappedTokensTo` from the exchange proxy', () => {
|
||||
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
||||
const recipientAddress = randomAddress();
|
||||
it('Tranfers an arbitrary ERC-20 Token', async () => {
|
||||
const amountOut = Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18);
|
||||
await zeroEx
|
||||
.transferTrappedTokensTo(token.address, amountOut, recipientAddress)
|
||||
.awaitTransactionSuccessAsync({ from: owner });
|
||||
const recipientAddressBalanceAferTransfer = await token.balanceOf(recipientAddress).callAsync();
|
||||
return expect(recipientAddressBalanceAferTransfer).to.bignumber.equal(amountOut);
|
||||
});
|
||||
it('Amount -1 transfers entire balance of ERC-20', async () => {
|
||||
const balanceOwner = await token.balanceOf(zeroEx.address).callAsync();
|
||||
await zeroEx
|
||||
.transferTrappedTokensTo(token.address, constants.MAX_UINT256, recipientAddress)
|
||||
.awaitTransactionSuccessAsync({ from: owner });
|
||||
const recipientAddressBalanceAferTransfer = await token.balanceOf(recipientAddress).callAsync();
|
||||
return expect(recipientAddressBalanceAferTransfer).to.bignumber.equal(balanceOwner);
|
||||
});
|
||||
it('Amount -1 transfers entire balance of ETH', async () => {
|
||||
const amountOut = new BigNumber(20);
|
||||
await env.web3Wrapper.awaitTransactionMinedAsync(
|
||||
await env.web3Wrapper.sendTransactionAsync({
|
||||
from: owner,
|
||||
to: zeroEx.address,
|
||||
value: amountOut,
|
||||
}),
|
||||
);
|
||||
const balanceOwner = await env.web3Wrapper.getBalanceInWeiAsync(zeroEx.address);
|
||||
await zeroEx
|
||||
.transferTrappedTokensTo(ETH_TOKEN_ADDRESS, constants.MAX_UINT256, recipientAddress)
|
||||
.awaitTransactionSuccessAsync({ from: owner });
|
||||
const recipientAddressBalanceAferTransfer = await env.web3Wrapper.getBalanceInWeiAsync(recipientAddress);
|
||||
return expect(recipientAddressBalanceAferTransfer).to.bignumber.equal(balanceOwner);
|
||||
});
|
||||
it('Transfers ETH ', async () => {
|
||||
const amountOut = new BigNumber(20);
|
||||
await env.web3Wrapper.awaitTransactionMinedAsync(
|
||||
await env.web3Wrapper.sendTransactionAsync({
|
||||
from: owner,
|
||||
to: zeroEx.address,
|
||||
value: amountOut,
|
||||
}),
|
||||
);
|
||||
await zeroEx
|
||||
.transferTrappedTokensTo(ETH_TOKEN_ADDRESS, amountOut.minus(1), recipientAddress)
|
||||
.awaitTransactionSuccessAsync({ from: owner });
|
||||
const recipientAddressBalance = await env.web3Wrapper.getBalanceInWeiAsync(recipientAddress);
|
||||
return expect(recipientAddressBalance).to.bignumber.be.equal(amountOut.minus(1));
|
||||
});
|
||||
it('Feature `transferTrappedTokensTo` can only be called by owner', async () => {
|
||||
const notOwner = randomAddress();
|
||||
return expect(
|
||||
zeroEx
|
||||
.transferTrappedTokensTo(ETH_TOKEN_ADDRESS, constants.MAX_UINT256, recipientAddress)
|
||||
.awaitTransactionSuccessAsync({ from: notOwner }),
|
||||
).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner, owner));
|
||||
});
|
||||
});
|
||||
});
|
@@ -19,6 +19,7 @@ export * from '../test/generated-wrappers/fixin_reentrancy_guard';
|
||||
export * from '../test/generated-wrappers/fixin_token_spender';
|
||||
export * from '../test/generated-wrappers/flash_wallet';
|
||||
export * from '../test/generated-wrappers/full_migration';
|
||||
export * from '../test/generated-wrappers/fund_recovery_feature';
|
||||
export * from '../test/generated-wrappers/i_batch_fill_native_orders_feature';
|
||||
export * from '../test/generated-wrappers/i_bootstrap_feature';
|
||||
export * from '../test/generated-wrappers/i_bridge_adapter';
|
||||
@@ -26,6 +27,7 @@ export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/i_erc20_transformer';
|
||||
export * from '../test/generated-wrappers/i_feature';
|
||||
export * from '../test/generated-wrappers/i_flash_wallet';
|
||||
export * from '../test/generated-wrappers/i_fund_recovery_feature';
|
||||
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';
|
||||
@@ -80,7 +82,6 @@ export * from '../test/generated-wrappers/meta_transactions_feature';
|
||||
export * from '../test/generated-wrappers/mixin_balancer';
|
||||
export * from '../test/generated-wrappers/mixin_balancer_v2';
|
||||
export * from '../test/generated-wrappers/mixin_bancor';
|
||||
export * from '../test/generated-wrappers/mixin_clipper';
|
||||
export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
|
@@ -52,6 +52,7 @@
|
||||
"test/generated-artifacts/FixinTokenSpender.json",
|
||||
"test/generated-artifacts/FlashWallet.json",
|
||||
"test/generated-artifacts/FullMigration.json",
|
||||
"test/generated-artifacts/FundRecoveryFeature.json",
|
||||
"test/generated-artifacts/IBatchFillNativeOrdersFeature.json",
|
||||
"test/generated-artifacts/IBootstrapFeature.json",
|
||||
"test/generated-artifacts/IBridgeAdapter.json",
|
||||
@@ -59,6 +60,7 @@
|
||||
"test/generated-artifacts/IERC20Transformer.json",
|
||||
"test/generated-artifacts/IFeature.json",
|
||||
"test/generated-artifacts/IFlashWallet.json",
|
||||
"test/generated-artifacts/IFundRecoveryFeature.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderFeature.json",
|
||||
"test/generated-artifacts/ILiquidityProviderSandbox.json",
|
||||
@@ -113,7 +115,6 @@
|
||||
"test/generated-artifacts/MixinBalancer.json",
|
||||
"test/generated-artifacts/MixinBalancerV2.json",
|
||||
"test/generated-artifacts/MixinBancor.json",
|
||||
"test/generated-artifacts/MixinClipper.json",
|
||||
"test/generated-artifacts/MixinCoFiX.json",
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
|
@@ -3,10 +3,14 @@ Protocol Fees
|
||||
###############################
|
||||
|
||||
An ETH protocol fee is paid by the Taker each time a `Limit Order <./orders.html#limit-orders>`_ is `filled <./functions.html>`_.
|
||||
The fee is proportional to the gas cost of filling an order and scales linearly with gas price. The cost is currently ``70k * tx.gasprice``.
|
||||
The fee is proportional to the gas cost of filling an order and scales linearly with gas price. The cost is currently ``0 * tx.gasprice``.
|
||||
At the end of every Staking Epoch, these fees are aggregated and distributed to the makers as a liquidity reward: the reward is proportional to the maker's collected fees and staked ZRX relative to other makers.
|
||||
To learn more about protocol fees and liquidity incentives, see the `Official Spec <https://github.com/0xProject/0x-protocol-specification/blob/master/staking/staking-specification.md>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
As of September 29, 2021, protocol fees have been removed for all order types in both Exchange V4 and V3 in accordance with `ZEIP-91 <https://0x.org/zrx/vote/zeip-91>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
`RFQ Orders <./orders.html#rfq-orders>`_ are introduced in Exchange V4, and there is currently no protocol fee for filling this type of order.
|
||||
|
@@ -1,2 +1,3 @@
|
||||
six
|
||||
sphinx-markdown-tables
|
||||
sphinx==3.5.4
|
||||
sphinx-markdown-tables
|
||||
|
@@ -46,12 +46,12 @@
|
||||
"test:generate_docs:circleci": "for i in ${npm_package_config_packagesWithDocPages}; do yarn generate_doc --package $i || break -1; done;",
|
||||
"bundlewatch": "bundlewatch",
|
||||
"lint": "wsrun --fast-exit --parallel --exclude-missing -p $PKG -c lint",
|
||||
"upgrade_org_deps": "node node_modules/@0x/monorepo-scripts/lib/upgrade_deps.js -p '@0x|ethereum-types'",
|
||||
"upgrade_org_deps": "node node_modules/@0x/monorepo-scripts/lib/upgrade_deps.js -p '@0x/|ethereum-types'",
|
||||
"upgrade_deps": "node node_modules/@0x/monorepo-scripts/lib/upgrade_deps.js",
|
||||
"verdaccio": "docker run --rm -i -p 4873:4873 0xorg/verdaccio"
|
||||
},
|
||||
"config": {
|
||||
"contractsPackages": "@0x/contracts-erc20 @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-zero-ex @0x/contracts-treasury",
|
||||
"contractsPackages": "@0x/contracts-erc20 @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-zero-ex @0x/contracts-treasury",
|
||||
"nonContractPackages": "@0x/migrations @0x/contract-wrappers @0x/contract-addresses @0x/contract-artifacts @0x/contract-wrappers-test @0x/asset-swapper",
|
||||
"ignoreTestsForPackages": "",
|
||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic",
|
||||
|
@@ -1,4 +1,90 @@
|
||||
[
|
||||
{
|
||||
"version": "16.29.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Remove `Clipper` as a custom liquidity source",
|
||||
"pr": 335
|
||||
}
|
||||
],
|
||||
"timestamp": 1633374058
|
||||
},
|
||||
{
|
||||
"version": "16.29.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Initial integration of neon-router (behind feature flag)",
|
||||
"pr": 295
|
||||
}
|
||||
],
|
||||
"timestamp": 1633350101
|
||||
},
|
||||
{
|
||||
"version": "16.28.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update ExchangeProxySwapQuoteConsumer for Multiplex V2 and friends",
|
||||
"pr": 282
|
||||
}
|
||||
],
|
||||
"timestamp": 1632957537
|
||||
},
|
||||
{
|
||||
"version": "16.27.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Remove protocol fees by setting `PROTOCOL_FEE_MULTIPLIER` to 0",
|
||||
"pr": 333
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "16.27.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631646242,
|
||||
"version": "16.27.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631639620,
|
||||
"version": "16.27.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "16.27.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix ApproximateBuys sampler to terminate if the buy amount is not met",
|
||||
"pr": 319
|
||||
}
|
||||
],
|
||||
"timestamp": 1631120757
|
||||
},
|
||||
{
|
||||
"version": "16.27.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Avalanche deployment",
|
||||
"pr": 312
|
||||
}
|
||||
],
|
||||
"timestamp": 1630459879
|
||||
},
|
||||
{
|
||||
"version": "16.26.2",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,42 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v16.29.1 - _October 4, 2021_
|
||||
|
||||
* Remove `Clipper` as a custom liquidity source (#335)
|
||||
|
||||
## v16.29.0 - _October 4, 2021_
|
||||
|
||||
* Initial integration of neon-router (behind feature flag) (#295)
|
||||
|
||||
## v16.28.0 - _September 29, 2021_
|
||||
|
||||
* Update ExchangeProxySwapQuoteConsumer for Multiplex V2 and friends (#282)
|
||||
|
||||
## v16.27.5 - _Invalid date_
|
||||
|
||||
* Remove protocol fees by setting `PROTOCOL_FEE_MULTIPLIER` to 0 (#333)
|
||||
|
||||
## v16.27.4 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v16.27.3 - _September 14, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v16.27.2 - _September 14, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v16.27.1 - _September 8, 2021_
|
||||
|
||||
* Fix ApproximateBuys sampler to terminate if the buy amount is not met (#319)
|
||||
|
||||
## v16.27.0 - _September 1, 2021_
|
||||
|
||||
* Avalanche deployment (#312)
|
||||
|
||||
## v16.26.2 - _August 31, 2021_
|
||||
|
||||
* chore: Curve new pools (CVX-CRX, MIM, atricrypto3)
|
||||
|
@@ -77,6 +77,7 @@ contract ApproximateBuys {
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < makerTokenAmounts.length; i++) {
|
||||
uint256 eps = 0;
|
||||
for (uint256 iter = 0; iter < APPROXIMATE_BUY_MAX_ITERATIONS; iter++) {
|
||||
// adjustedSellAmount = previousSellAmount * (target/actual) * JUMP_MULTIPLIER
|
||||
sellAmount = _safeGetPartialAmountCeil(
|
||||
@@ -108,7 +109,7 @@ contract ApproximateBuys {
|
||||
buyAmount = _buyAmount;
|
||||
// If we've reached our goal, exit early
|
||||
if (buyAmount >= makerTokenAmounts[i]) {
|
||||
uint256 eps =
|
||||
eps =
|
||||
(buyAmount - makerTokenAmounts[i]) * ONE_HUNDED_PERCENT_BPS /
|
||||
makerTokenAmounts[i];
|
||||
if (eps <= APPROXIMATE_BUY_TARGET_EPSILON_BPS) {
|
||||
@@ -116,6 +117,9 @@ contract ApproximateBuys {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (eps == 0 || eps > APPROXIMATE_BUY_TARGET_EPSILON_BPS) {
|
||||
break;
|
||||
}
|
||||
// We do our best to close in on the requested amount, but we can either over buy or under buy and exit
|
||||
// if we hit a max iteration limit
|
||||
// We scale the sell amount to get the approximate target
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/asset-swapper",
|
||||
"version": "16.26.2",
|
||||
"version": "16.29.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -58,20 +58,21 @@
|
||||
"registry": "git@github.com:0xProject/gitpkg-registry.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/contract-wrappers": "^13.17.5",
|
||||
"@0x/contracts-erc20": "^3.3.17",
|
||||
"@0x/contracts-zero-ex": "^0.27.0",
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/protocol-utils": "^1.8.3",
|
||||
"@0x/quote-server": "^6.0.2",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"@0x/assert": "^3.0.29",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/contract-wrappers": "^13.18.0",
|
||||
"@0x/contracts-erc20": "^3.3.20",
|
||||
"@0x/contracts-zero-ex": "^0.29.1",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/json-schemas": "^6.3.0",
|
||||
"@0x/neon-router": "^0.1.3",
|
||||
"@0x/protocol-utils": "^1.9.2",
|
||||
"@0x/quote-server": "^6.0.6",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"@balancer-labs/sor": "0.3.2",
|
||||
"@bancor/sdk": "0.2.9",
|
||||
"@ethersproject/abi": "^5.0.1",
|
||||
@@ -83,7 +84,7 @@
|
||||
"axios-mock-adapter": "^1.19.0",
|
||||
"cream-sor": "^0.3.3",
|
||||
"decimal.js": "^10.2.0",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"fast-abi": "^0.0.2",
|
||||
"graphql": "^15.4.0",
|
||||
@@ -92,20 +93,20 @@
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.6.0",
|
||||
"@0x/abi-gen": "^5.6.2",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-exchange": "^3.2.38",
|
||||
"@0x/contracts-exchange-libs": "^4.3.37",
|
||||
"@0x/contracts-gen": "^2.0.38",
|
||||
"@0x/contracts-test-utils": "^5.4.9",
|
||||
"@0x/contracts-utils": "^4.7.17",
|
||||
"@0x/contracts-gen": "^2.0.40",
|
||||
"@0x/contracts-test-utils": "^5.4.11",
|
||||
"@0x/contracts-utils": "^4.8.1",
|
||||
"@0x/mesh-rpc-client": "^9.4.2",
|
||||
"@0x/migrations": "^8.1.3",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/migrations": "^8.1.8",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/subproviders": "^6.6.0",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "12.12.54",
|
||||
|
@@ -38,7 +38,7 @@ const DEFAULT_ORDER_PRUNER_OPTS: OrderPrunerOpts = {
|
||||
|
||||
// 6 seconds polling interval
|
||||
const PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS = 6000;
|
||||
const PROTOCOL_FEE_MULTIPLIER = new BigNumber(70000);
|
||||
const PROTOCOL_FEE_MULTIPLIER = new BigNumber(0);
|
||||
|
||||
// default 50% buffer for selecting native orders to be aggregated with other sources
|
||||
const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5;
|
||||
@@ -50,7 +50,7 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
|
||||
samplerGasLimit: 500e6,
|
||||
ethGasStationUrl: ETH_GAS_STATION_API_URL,
|
||||
rfqt: {
|
||||
takerApiKeyWhitelist: [],
|
||||
integratorsWhitelist: [],
|
||||
makerAssetOfferings: {},
|
||||
txOriginBlacklist: new Set(),
|
||||
},
|
||||
|
@@ -88,6 +88,7 @@ export {
|
||||
ExchangeProxyContractOpts,
|
||||
ExchangeProxyRefundReceiver,
|
||||
GetExtensionContractTypeOpts,
|
||||
Integrator,
|
||||
LogFunction,
|
||||
MarketBuySwapQuote,
|
||||
MarketOperation,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { ChainId, ContractAddresses } from '@0x/contract-addresses';
|
||||
import { IZeroExContract, WETH9Contract } from '@0x/contract-wrappers';
|
||||
import { MultiplexFeatureContract } from '@0x/contracts-zero-ex';
|
||||
import { IZeroExContract } from '@0x/contract-wrappers';
|
||||
import { TransformERC20FeatureContract } from '@0x/contracts-zero-ex';
|
||||
import {
|
||||
encodeAffiliateFeeTransformerData,
|
||||
encodeCurveLiquidityProviderData,
|
||||
@@ -51,6 +51,7 @@ import {
|
||||
import {
|
||||
multiplexPlpEncoder,
|
||||
multiplexRfqEncoder,
|
||||
MultiplexSubcall,
|
||||
multiplexTransformERC20Encoder,
|
||||
multiplexUniswapEncoder,
|
||||
} from './multiplex_encoders';
|
||||
@@ -82,7 +83,6 @@ const FAKE_PROVIDER: any = {
|
||||
return;
|
||||
},
|
||||
};
|
||||
const DUMMY_WETH_CONTRACT = new WETH9Contract(NULL_ADDRESS, FAKE_PROVIDER);
|
||||
|
||||
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
public readonly chainId: ChainId;
|
||||
@@ -95,7 +95,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
};
|
||||
|
||||
private readonly _exchangeProxy: IZeroExContract;
|
||||
private readonly _multiplex: MultiplexFeatureContract;
|
||||
private readonly _transformERC20Feature: TransformERC20FeatureContract;
|
||||
|
||||
constructor(public readonly contractAddresses: ContractAddresses, options: Partial<SwapQuoteConsumerOpts> = {}) {
|
||||
const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
||||
@@ -103,7 +103,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
this.chainId = chainId;
|
||||
this.contractAddresses = contractAddresses;
|
||||
this._exchangeProxy = new IZeroExContract(contractAddresses.exchangeProxy, FAKE_PROVIDER);
|
||||
this._multiplex = new MultiplexFeatureContract(contractAddresses.exchangeProxy, FAKE_PROVIDER);
|
||||
this._transformERC20Feature = new TransformERC20FeatureContract(contractAddresses.exchangeProxy, FAKE_PROVIDER);
|
||||
this.transformerNonces = {
|
||||
wethTransformer: findTransformerNonce(
|
||||
contractAddresses.transformers.wethTransformer,
|
||||
@@ -338,7 +338,10 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
|
||||
if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) {
|
||||
return {
|
||||
calldataHexString: this._encodeMultiplexBatchFillCalldata({ ...quote, orders: slippedOrders }),
|
||||
calldataHexString: this._encodeMultiplexBatchFillCalldata(
|
||||
{ ...quote, orders: slippedOrders },
|
||||
optsWithDefaults,
|
||||
),
|
||||
ethAmount,
|
||||
toAddress: this._exchangeProxy.address,
|
||||
allowanceTarget: this._exchangeProxy.address,
|
||||
@@ -473,17 +476,27 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
}
|
||||
}
|
||||
|
||||
// Return any unspent sell tokens.
|
||||
const payTakerTokens = [sellToken];
|
||||
// Return any unspent intermediate tokens for two-hop swaps.
|
||||
if (quote.isTwoHop) {
|
||||
payTakerTokens.push(intermediateToken);
|
||||
}
|
||||
// Return any unspent ETH. If ETH is the buy token, it will
|
||||
// be returned in TransformERC20Feature rather than PayTakerTransformer.
|
||||
if (!isToETH) {
|
||||
payTakerTokens.push(ETH_TOKEN_ADDRESS);
|
||||
}
|
||||
// The final transformer will send all funds to the taker.
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.payTakerTransformer,
|
||||
data: encodePayTakerTransformerData({
|
||||
tokens: [sellToken, buyToken, ETH_TOKEN_ADDRESS].concat(quote.isTwoHop ? intermediateToken : []),
|
||||
tokens: payTakerTokens,
|
||||
amounts: [],
|
||||
}),
|
||||
});
|
||||
|
||||
const calldataHexString = this._exchangeProxy
|
||||
.transformERC20(
|
||||
const calldataHexString = this._transformERC20Feature
|
||||
.transformERC20Staging(
|
||||
isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
|
||||
isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||
shouldSellEntireBalance ? MAX_UINT256 : sellAmount,
|
||||
@@ -509,8 +522,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
throw new Error('Execution not supported for Exchange Proxy quotes');
|
||||
}
|
||||
|
||||
private _encodeMultiplexBatchFillCalldata(quote: SwapQuote): string {
|
||||
const wrappedBatchCalls = [];
|
||||
private _encodeMultiplexBatchFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string {
|
||||
const subcalls = [];
|
||||
for_loop: for (const [i, order] of quote.orders.entries()) {
|
||||
switch_statement: switch (order.source) {
|
||||
case ERC20BridgeSource.Native:
|
||||
@@ -519,8 +532,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
// before calling this function.
|
||||
throw new Error('Multiplex batch fill only supported for RFQ native orders');
|
||||
}
|
||||
wrappedBatchCalls.push({
|
||||
selector: this._exchangeProxy.getSelector('_fillRfqOrder'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.Rfq,
|
||||
sellAmount: order.takerAmount,
|
||||
data: multiplexRfqEncoder.encode({
|
||||
order: order.fillData.order,
|
||||
@@ -530,8 +543,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
break switch_statement;
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
wrappedBatchCalls.push({
|
||||
selector: this._multiplex.getSelector('_sellToUniswap'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.UniswapV2,
|
||||
sellAmount: order.takerAmount,
|
||||
data: multiplexUniswapEncoder.encode({
|
||||
tokens: (order.fillData as UniswapV2FillData).tokenAddressPath,
|
||||
@@ -540,8 +553,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
});
|
||||
break switch_statement;
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
wrappedBatchCalls.push({
|
||||
selector: this._multiplex.getSelector('_sellToLiquidityProvider'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.LiquidityProvider,
|
||||
sellAmount: order.takerAmount,
|
||||
data: multiplexPlpEncoder.encode({
|
||||
provider: (order.fillData as LiquidityProviderFillData).poolAddress,
|
||||
@@ -551,8 +564,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
break switch_statement;
|
||||
case ERC20BridgeSource.UniswapV3:
|
||||
const fillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
|
||||
wrappedBatchCalls.push({
|
||||
selector: this._exchangeProxy.getSelector('sellTokenForTokenToUniswapV3'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.UniswapV3,
|
||||
sellAmount: order.takerAmount,
|
||||
data: fillData.uniswapPath,
|
||||
});
|
||||
@@ -571,54 +584,59 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
{
|
||||
deploymentNonce: this.transformerNonces.payTakerTransformer,
|
||||
data: encodePayTakerTransformerData({
|
||||
tokens: [quote.takerToken, quote.makerToken],
|
||||
tokens: [quote.takerToken],
|
||||
amounts: [],
|
||||
}),
|
||||
},
|
||||
];
|
||||
wrappedBatchCalls.push({
|
||||
selector: this._exchangeProxy.getSelector('_transformERC20'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.TransformERC20,
|
||||
sellAmount: BigNumber.sum(...quote.orders.slice(i).map(o => o.takerAmount)),
|
||||
data: multiplexTransformERC20Encoder.encode({
|
||||
transformations,
|
||||
ethValue: constants.ZERO_AMOUNT,
|
||||
}),
|
||||
});
|
||||
break for_loop;
|
||||
}
|
||||
}
|
||||
return this._exchangeProxy
|
||||
.batchFill(
|
||||
{
|
||||
inputToken: quote.takerToken,
|
||||
outputToken: quote.makerToken,
|
||||
sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount,
|
||||
calls: wrappedBatchCalls,
|
||||
},
|
||||
quote.worstCaseQuoteInfo.makerAmount,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
if (opts.isFromETH) {
|
||||
return this._exchangeProxy
|
||||
.multiplexBatchSellEthForToken(quote.makerToken, subcalls, quote.worstCaseQuoteInfo.makerAmount)
|
||||
.getABIEncodedTransactionData();
|
||||
} else if (opts.isToETH) {
|
||||
return this._exchangeProxy
|
||||
.multiplexBatchSellTokenForEth(
|
||||
quote.takerToken,
|
||||
subcalls,
|
||||
quote.worstCaseQuoteInfo.totalTakerAmount,
|
||||
quote.worstCaseQuoteInfo.makerAmount,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
} else {
|
||||
return this._exchangeProxy
|
||||
.multiplexBatchSellTokenForToken(
|
||||
quote.takerToken,
|
||||
quote.makerToken,
|
||||
subcalls,
|
||||
quote.worstCaseQuoteInfo.totalTakerAmount,
|
||||
quote.worstCaseQuoteInfo.makerAmount,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
}
|
||||
}
|
||||
|
||||
private _encodeMultiplexMultiHopFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string {
|
||||
const wrappedMultiHopCalls = [];
|
||||
const tokens: string[] = [];
|
||||
if (opts.isFromETH) {
|
||||
wrappedMultiHopCalls.push({
|
||||
selector: DUMMY_WETH_CONTRACT.getSelector('deposit'),
|
||||
data: NULL_BYTES,
|
||||
});
|
||||
tokens.push(ETH_TOKEN_ADDRESS);
|
||||
}
|
||||
const subcalls = [];
|
||||
const [firstHopOrder, secondHopOrder] = quote.orders;
|
||||
const intermediateToken = firstHopOrder.makerToken;
|
||||
tokens.push(quote.takerToken, intermediateToken, quote.makerToken);
|
||||
const tokens = [quote.takerToken, intermediateToken, quote.makerToken];
|
||||
|
||||
for (const order of [firstHopOrder, secondHopOrder]) {
|
||||
switch (order.source) {
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
wrappedMultiHopCalls.push({
|
||||
selector: this._multiplex.getSelector('_sellToUniswap'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.UniswapV2,
|
||||
data: multiplexUniswapEncoder.encode({
|
||||
tokens: (order.fillData as UniswapV2FillData).tokenAddressPath,
|
||||
isSushi: order.source === ERC20BridgeSource.SushiSwap,
|
||||
@@ -626,39 +644,49 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
});
|
||||
break;
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
wrappedMultiHopCalls.push({
|
||||
selector: this._multiplex.getSelector('_sellToLiquidityProvider'),
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.LiquidityProvider,
|
||||
data: multiplexPlpEncoder.encode({
|
||||
provider: (order.fillData as LiquidityProviderFillData).poolAddress,
|
||||
auxiliaryData: NULL_BYTES,
|
||||
}),
|
||||
});
|
||||
break;
|
||||
case ERC20BridgeSource.UniswapV3:
|
||||
subcalls.push({
|
||||
id: MultiplexSubcall.UniswapV3,
|
||||
data: (order.fillData as FinalUniswapV3FillData).uniswapPath,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// Note: we'll need to redeploy TransformERC20Feature before we can
|
||||
// use other sources
|
||||
// Should never happen because we check `isMultiplexMultiHopFillCompatible`
|
||||
// before calling this function.
|
||||
throw new Error(`Multiplex multi-hop unsupported source: ${order.source}`);
|
||||
}
|
||||
}
|
||||
if (opts.isToETH) {
|
||||
wrappedMultiHopCalls.push({
|
||||
selector: DUMMY_WETH_CONTRACT.getSelector('withdraw'),
|
||||
data: NULL_BYTES,
|
||||
});
|
||||
tokens.push(ETH_TOKEN_ADDRESS);
|
||||
}
|
||||
return this._exchangeProxy
|
||||
.multiHopFill(
|
||||
{
|
||||
if (opts.isFromETH) {
|
||||
return this._exchangeProxy
|
||||
.multiplexMultiHopSellEthForToken(tokens, subcalls, quote.worstCaseQuoteInfo.makerAmount)
|
||||
.getABIEncodedTransactionData();
|
||||
} else if (opts.isToETH) {
|
||||
return this._exchangeProxy
|
||||
.multiplexMultiHopSellTokenForEth(
|
||||
tokens,
|
||||
sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount,
|
||||
calls: wrappedMultiHopCalls,
|
||||
},
|
||||
quote.worstCaseQuoteInfo.makerAmount,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
subcalls,
|
||||
quote.worstCaseQuoteInfo.totalTakerAmount,
|
||||
quote.worstCaseQuoteInfo.makerAmount,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
} else {
|
||||
return this._exchangeProxy
|
||||
.multiplexMultiHopSellTokenForToken(
|
||||
tokens,
|
||||
subcalls,
|
||||
quote.worstCaseQuoteInfo.totalTakerAmount,
|
||||
quote.worstCaseQuoteInfo.makerAmount,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,17 @@
|
||||
import { RfqOrder, SIGNATURE_ABI } from '@0x/protocol-utils';
|
||||
import { AbiEncoder } from '@0x/utils';
|
||||
|
||||
export enum MultiplexSubcall {
|
||||
Invalid,
|
||||
Rfq,
|
||||
Otc,
|
||||
UniswapV2,
|
||||
UniswapV3,
|
||||
LiquidityProvider,
|
||||
TransformERC20,
|
||||
BatchSell,
|
||||
MultiHopSell,
|
||||
}
|
||||
export const multiplexTransformERC20Encoder = AbiEncoder.create([
|
||||
{
|
||||
name: 'transformations',
|
||||
@@ -10,7 +21,6 @@ export const multiplexTransformERC20Encoder = AbiEncoder.create([
|
||||
{ name: 'data', type: 'bytes' },
|
||||
],
|
||||
},
|
||||
{ name: 'ethValue', type: 'uint256' },
|
||||
]);
|
||||
export const multiplexRfqEncoder = AbiEncoder.create([
|
||||
{ name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI },
|
||||
|
@@ -32,10 +32,6 @@ export function isMultiplexBatchFillCompatible(quote: SwapQuote, opts: ExchangeP
|
||||
if (quote.isTwoHop) {
|
||||
return false;
|
||||
}
|
||||
// batchFill does not support WETH wrapping/unwrapping at the moment
|
||||
if (opts.isFromETH || opts.isToETH) {
|
||||
return false;
|
||||
}
|
||||
if (quote.orders.map(o => o.type).includes(FillQuoteTransformerOrderType.Limit)) {
|
||||
return false;
|
||||
}
|
||||
@@ -49,6 +45,7 @@ const MULTIPLEX_MULTIHOP_FILL_SOURCES = [
|
||||
ERC20BridgeSource.UniswapV2,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.UniswapV3,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@@ -75,6 +75,7 @@ export class SwapQuoter {
|
||||
private readonly _marketOperationUtils: MarketOperationUtils;
|
||||
private readonly _rfqtOptions?: SwapQuoterRfqOpts;
|
||||
private readonly _quoteRequestorHttpClient: AxiosInstance;
|
||||
private readonly _integratorIdsSet: Set<string>;
|
||||
|
||||
/**
|
||||
* Instantiates a new SwapQuoter instance
|
||||
@@ -164,6 +165,9 @@ export class SwapQuoter {
|
||||
httpsAgent: new HttpsAgent({ keepAlive: true, timeout: KEEP_ALIVE_TTL }),
|
||||
...(rfqt ? rfqt.axiosInstanceOpts : {}),
|
||||
});
|
||||
|
||||
const integratorIds = this._rfqtOptions?.integratorsWhitelist.map(integrator => integrator.integratorId) || [];
|
||||
this._integratorIdsSet = new Set(integratorIds);
|
||||
}
|
||||
|
||||
public async getBatchMarketBuySwapQuoteAsync(
|
||||
@@ -359,6 +363,7 @@ export class SwapQuoter {
|
||||
const cloneOpts = _.omit(opts, 'gasPrice') as GetMarketOrdersOpts;
|
||||
const calcOpts: GetMarketOrdersOpts = {
|
||||
...cloneOpts,
|
||||
gasPrice,
|
||||
feeSchedule: _.mapValues(opts.feeSchedule, gasCost => (fillData: FillData) =>
|
||||
gasCost === undefined ? 0 : gasPrice.times(gasCost(fillData)),
|
||||
),
|
||||
@@ -414,12 +419,11 @@ export class SwapQuoter {
|
||||
return isOpenOrder && !willOrderExpire && isFeeTypeAllowed;
|
||||
}; // tslint:disable-line:semicolon
|
||||
|
||||
private _isApiKeyWhitelisted(apiKey: string | undefined): boolean {
|
||||
if (!apiKey) {
|
||||
private _isIntegratorIdWhitelisted(integratorId: string | undefined): boolean {
|
||||
if (!integratorId) {
|
||||
return false;
|
||||
}
|
||||
const whitelistedApiKeys = this._rfqtOptions ? this._rfqtOptions.takerApiKeyWhitelist : [];
|
||||
return whitelistedApiKeys.includes(apiKey);
|
||||
return this._integratorIdsSet.has(integratorId);
|
||||
}
|
||||
|
||||
private _isTxOriginBlacklisted(txOrigin: string | undefined): boolean {
|
||||
@@ -438,19 +442,19 @@ export class SwapQuoter {
|
||||
return rfqt;
|
||||
}
|
||||
// tslint:disable-next-line: boolean-naming
|
||||
const { apiKey, nativeExclusivelyRFQ, intentOnFilling, txOrigin } = rfqt;
|
||||
const { integrator, nativeExclusivelyRFQ, intentOnFilling, txOrigin } = rfqt;
|
||||
// If RFQ-T is enabled and `nativeExclusivelyRFQ` is set, then `ERC20BridgeSource.Native` should
|
||||
// never be excluded.
|
||||
if (nativeExclusivelyRFQ === true && !sourceFilters.isAllowed(ERC20BridgeSource.Native)) {
|
||||
throw new Error('Native liquidity cannot be excluded if "rfqt.nativeExclusivelyRFQ" is set');
|
||||
}
|
||||
|
||||
// If an API key was provided, but the key is not whitelisted, raise a warning and disable RFQ
|
||||
if (!this._isApiKeyWhitelisted(apiKey)) {
|
||||
// If an integrator ID was provided, but the ID is not whitelisted, raise a warning and disable RFQ
|
||||
if (!this._isIntegratorIdWhitelisted(integrator.integratorId)) {
|
||||
if (this._rfqtOptions && this._rfqtOptions.warningLogger) {
|
||||
this._rfqtOptions.warningLogger(
|
||||
{
|
||||
apiKey,
|
||||
...integrator,
|
||||
},
|
||||
'Attempt at using an RFQ API key that is not whitelisted. Disabling RFQ for the request lifetime.',
|
||||
);
|
||||
@@ -474,7 +478,7 @@ export class SwapQuoter {
|
||||
// Otherwise check other RFQ options
|
||||
if (
|
||||
intentOnFilling && // The requestor is asking for a firm quote
|
||||
this._isApiKeyWhitelisted(apiKey) && // A valid API key was provided
|
||||
this._isIntegratorIdWhitelisted(integrator.integratorId) && // A valid API key was provided
|
||||
sourceFilters.isAllowed(ERC20BridgeSource.Native) // Native liquidity is not excluded
|
||||
) {
|
||||
if (!txOrigin || txOrigin === constants.NULL_ADDRESS) {
|
||||
|
@@ -243,7 +243,7 @@ export interface RfqmRequestOptions extends RfqRequestOpts {
|
||||
export interface RfqRequestOpts {
|
||||
takerAddress: string;
|
||||
txOrigin: string;
|
||||
apiKey: string;
|
||||
integrator: Integrator;
|
||||
intentOnFilling: boolean;
|
||||
isIndicative?: boolean;
|
||||
makerEndpointMaxResponseTimeMs?: number;
|
||||
@@ -256,7 +256,7 @@ export interface RfqRequestOpts {
|
||||
/**
|
||||
* gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount
|
||||
*/
|
||||
export interface SwapQuoteRequestOpts extends GetMarketOrdersOpts {
|
||||
export interface SwapQuoteRequestOpts extends Omit<GetMarketOrdersOpts, 'gasPrice'> {
|
||||
gasPrice?: BigNumber;
|
||||
rfqt?: RfqRequestOpts;
|
||||
}
|
||||
@@ -293,8 +293,14 @@ export interface RfqFirmQuoteValidator {
|
||||
getRfqtTakerFillableAmountsAsync(quotes: RfqOrder[]): Promise<BigNumber[]>;
|
||||
}
|
||||
|
||||
export interface Integrator {
|
||||
integratorId: string;
|
||||
label: string;
|
||||
whitelistIntegratorUrls?: string[];
|
||||
}
|
||||
|
||||
export interface SwapQuoterRfqOpts {
|
||||
takerApiKeyWhitelist: string[];
|
||||
integratorsWhitelist: Integrator[];
|
||||
makerAssetOfferings: RfqMakerAssetOfferings;
|
||||
txOriginBlacklist: Set<string>;
|
||||
altRfqCreds?: {
|
||||
|
@@ -31,6 +31,7 @@ import {
|
||||
NULL_ADDRESS,
|
||||
PANCAKESWAP_ROUTER_BY_CHAIN_ID,
|
||||
PANCAKESWAPV2_ROUTER_BY_CHAIN_ID,
|
||||
PANGOLIN_ROUTER_BY_CHAIN_ID,
|
||||
POLYDEX_ROUTER_BY_CHAIN_ID,
|
||||
QUICKSWAP_ROUTER_BY_CHAIN_ID,
|
||||
SADDLE_MAINNET_INFOS,
|
||||
@@ -41,6 +42,7 @@ import {
|
||||
SNOWSWAP_MAINNET_INFOS,
|
||||
SUSHISWAP_ROUTER_BY_CHAIN_ID,
|
||||
SWERVE_MAINNET_INFOS,
|
||||
TRADER_JOE_ROUTER_BY_CHAIN_ID,
|
||||
UNISWAPV2_ROUTER_BY_CHAIN_ID,
|
||||
WAULTSWAP_ROUTER_BY_CHAIN_ID,
|
||||
XSIGMA_MAINNET_INFOS,
|
||||
@@ -439,7 +441,9 @@ export function uniswapV2LikeRouterAddress(
|
||||
| ERC20BridgeSource.WaultSwap
|
||||
| ERC20BridgeSource.Polydex
|
||||
| ERC20BridgeSource.ShibaSwap
|
||||
| ERC20BridgeSource.JetSwap,
|
||||
| ERC20BridgeSource.JetSwap
|
||||
| ERC20BridgeSource.TraderJoe
|
||||
| ERC20BridgeSource.Pangolin,
|
||||
): string {
|
||||
switch (source) {
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
@@ -476,6 +480,10 @@ export function uniswapV2LikeRouterAddress(
|
||||
return SHIBASWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
return JETSWAP_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
return PANGOLIN_ROUTER_BY_CHAIN_ID[chainId];
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
return TRADER_JOE_ROUTER_BY_CHAIN_ID[chainId];
|
||||
default:
|
||||
throw new Error(`Unknown UniswapV2 like source ${source}`);
|
||||
}
|
||||
|
@@ -56,6 +56,7 @@ function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaultValue:
|
||||
[ChainId.BSC]: defaultValue,
|
||||
[ChainId.Polygon]: defaultValue,
|
||||
[ChainId.PolygonMumbai]: defaultValue,
|
||||
[ChainId.Avalanche]: defaultValue,
|
||||
...(rest || {}),
|
||||
};
|
||||
}
|
||||
@@ -98,7 +99,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
ERC20BridgeSource.UniswapV3,
|
||||
ERC20BridgeSource.CurveV2,
|
||||
ERC20BridgeSource.ShibaSwap,
|
||||
ERC20BridgeSource.Clipper,
|
||||
]),
|
||||
[ChainId.Ropsten]: new SourceFilters([
|
||||
ERC20BridgeSource.Kyber,
|
||||
@@ -157,6 +157,12 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
ERC20BridgeSource.JetSwap,
|
||||
ERC20BridgeSource.IronSwap,
|
||||
]),
|
||||
[ChainId.Avalanche]: new SourceFilters([
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Pangolin,
|
||||
ERC20BridgeSource.TraderJoe,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
]),
|
||||
},
|
||||
new SourceFilters([]),
|
||||
);
|
||||
@@ -199,7 +205,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
ERC20BridgeSource.UniswapV3,
|
||||
ERC20BridgeSource.CurveV2,
|
||||
ERC20BridgeSource.ShibaSwap,
|
||||
ERC20BridgeSource.Clipper,
|
||||
]),
|
||||
[ChainId.Ropsten]: new SourceFilters([
|
||||
ERC20BridgeSource.Kyber,
|
||||
@@ -258,6 +263,12 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
ERC20BridgeSource.JetSwap,
|
||||
ERC20BridgeSource.IronSwap,
|
||||
]),
|
||||
[ChainId.Avalanche]: new SourceFilters([
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Pangolin,
|
||||
ERC20BridgeSource.TraderJoe,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
]),
|
||||
},
|
||||
new SourceFilters([]),
|
||||
);
|
||||
@@ -265,7 +276,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
|
||||
/**
|
||||
* 0x Protocol Fee Multiplier
|
||||
*/
|
||||
export const PROTOCOL_FEE_MULTIPLIER = new BigNumber(70000);
|
||||
export const PROTOCOL_FEE_MULTIPLIER = new BigNumber(0);
|
||||
|
||||
/**
|
||||
* Sources to poll for ETH fee price estimates.
|
||||
@@ -276,6 +287,7 @@ export const FEE_QUOTE_SOURCES_BY_CHAIN_ID = valueByChainId<ERC20BridgeSource[]>
|
||||
[ChainId.BSC]: [ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.Mooniswap, ERC20BridgeSource.SushiSwap],
|
||||
[ChainId.Ropsten]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap],
|
||||
[ChainId.Polygon]: [ERC20BridgeSource.QuickSwap, ERC20BridgeSource.SushiSwap],
|
||||
[ChainId.Avalanche]: [ERC20BridgeSource.Pangolin, ERC20BridgeSource.TraderJoe, ERC20BridgeSource.SushiSwap],
|
||||
},
|
||||
[],
|
||||
);
|
||||
@@ -416,6 +428,13 @@ export const POLYGON_TOKENS = {
|
||||
WEXPOLY: '0x4c4bf319237d98a30a929a96112effa8da3510eb',
|
||||
};
|
||||
|
||||
export const AVALANCHE_TOKENS = {
|
||||
WAVAX: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7',
|
||||
WETH: '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab',
|
||||
USDT: '0xc7198437980c041c805a1edcba50c1ce5db95118',
|
||||
DAI: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70',
|
||||
};
|
||||
|
||||
export const CURVE_POOLS = {
|
||||
compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56', // 0.Compound
|
||||
// 1.USDT is dead
|
||||
@@ -569,6 +588,12 @@ export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>(
|
||||
POLYGON_TOKENS.USDT,
|
||||
POLYGON_TOKENS.WBTC,
|
||||
],
|
||||
[ChainId.Avalanche]: [
|
||||
AVALANCHE_TOKENS.WAVAX,
|
||||
AVALANCHE_TOKENS.WETH,
|
||||
AVALANCHE_TOKENS.DAI,
|
||||
AVALANCHE_TOKENS.USDT,
|
||||
],
|
||||
},
|
||||
[],
|
||||
);
|
||||
@@ -594,6 +619,9 @@ export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId<TokenAdj
|
||||
[ChainId.Polygon]: new TokenAdjacencyGraphBuilder({
|
||||
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Polygon],
|
||||
}).build(),
|
||||
[ChainId.Avalanche]: new TokenAdjacencyGraphBuilder({
|
||||
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Avalanche],
|
||||
}).build(),
|
||||
},
|
||||
new TokenAdjacencyGraphBuilder({ default: [] }).build(),
|
||||
);
|
||||
@@ -607,6 +635,7 @@ export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>(
|
||||
[ChainId.Rinkeby]: getContractAddressesForChainOrThrow(ChainId.Rinkeby).etherToken,
|
||||
[ChainId.Kovan]: getContractAddressesForChainOrThrow(ChainId.Kovan).etherToken,
|
||||
[ChainId.Polygon]: getContractAddressesForChainOrThrow(ChainId.Polygon).etherToken,
|
||||
[ChainId.Avalanche]: getContractAddressesForChainOrThrow(ChainId.Avalanche).etherToken,
|
||||
},
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
@@ -1219,6 +1248,7 @@ export const SUSHISWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
[ChainId.BSC]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
|
||||
[ChainId.Ropsten]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
|
||||
[ChainId.Polygon]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
|
||||
[ChainId.Avalanche]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
|
||||
},
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
@@ -1450,22 +1480,6 @@ export const LIDO_INFO_BY_CHAIN = valueByChainId<LidoInfo>(
|
||||
},
|
||||
);
|
||||
|
||||
export const CLIPPER_INFO_BY_CHAIN = valueByChainId(
|
||||
{
|
||||
[ChainId.Mainnet]: {
|
||||
poolAddress: '0xe82906b6b1b04f631d126c974af57a3a7b6a99d9',
|
||||
tokens: [
|
||||
MAINNET_TOKENS.WETH, // technically ETH but our sampler and mixin handle this
|
||||
MAINNET_TOKENS.WBTC,
|
||||
MAINNET_TOKENS.USDC,
|
||||
MAINNET_TOKENS.USDT,
|
||||
MAINNET_TOKENS.DAI,
|
||||
],
|
||||
},
|
||||
},
|
||||
{ poolAddress: NULL_ADDRESS, tokens: [] },
|
||||
);
|
||||
|
||||
export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer';
|
||||
export const BALANCER_TOP_POOLS_FETCHED = 250;
|
||||
export const BALANCER_MAX_POOLS_FETCHED = 3;
|
||||
@@ -1591,6 +1605,37 @@ export const JETSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
|
||||
export const PANGOLIN_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
{
|
||||
[ChainId.Avalanche]: '0xe54ca86531e17ef3616d22ca28b0d458b6c89106',
|
||||
},
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
|
||||
export const TRADER_JOE_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
|
||||
{
|
||||
[ChainId.Avalanche]: '0x60ae616a2155ee3d9a68541ba4544862310933d4',
|
||||
},
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
|
||||
export const VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID = valueByChainId<ERC20BridgeSource[]>(
|
||||
{
|
||||
[ChainId.Mainnet]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3],
|
||||
[ChainId.BSC]: [
|
||||
ERC20BridgeSource.PancakeSwap,
|
||||
ERC20BridgeSource.PancakeSwapV2,
|
||||
ERC20BridgeSource.BakerySwap,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.ApeSwap,
|
||||
ERC20BridgeSource.CafeSwap,
|
||||
ERC20BridgeSource.CheeseSwap,
|
||||
ERC20BridgeSource.JulSwap,
|
||||
],
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const uniswapV2CloneGasSchedule = (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 90e3;
|
||||
@@ -1696,7 +1741,6 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
return gas;
|
||||
},
|
||||
[ERC20BridgeSource.Lido]: () => 226e3,
|
||||
[ERC20BridgeSource.Clipper]: () => 170e3,
|
||||
|
||||
//
|
||||
// BSC
|
||||
@@ -1719,6 +1763,12 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
[ERC20BridgeSource.Dfyn]: uniswapV2CloneGasSchedule,
|
||||
[ERC20BridgeSource.Polydex]: uniswapV2CloneGasSchedule,
|
||||
[ERC20BridgeSource.JetSwap]: uniswapV2CloneGasSchedule,
|
||||
|
||||
//
|
||||
// Avalanche
|
||||
//
|
||||
[ERC20BridgeSource.Pangolin]: uniswapV2CloneGasSchedule,
|
||||
[ERC20BridgeSource.TraderJoe]: uniswapV2CloneGasSchedule,
|
||||
};
|
||||
|
||||
export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = { ...DEFAULT_GAS_SCHEDULE };
|
||||
@@ -1727,7 +1777,7 @@ export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(20000);
|
||||
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
|
||||
export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
|
||||
export const DEFAULT_GET_MARKET_ORDERS_OPTS: Omit<GetMarketOrdersOpts, 'gasPrice'> = {
|
||||
// tslint:disable-next-line: custom-no-magic-numbers
|
||||
runLimit: 2 ** 15,
|
||||
excludedSources: [],
|
||||
|
@@ -71,7 +71,25 @@ function hasLiquidity(fills: Fill[]): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function nativeOrdersToFills(
|
||||
export function ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
ethAmount,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
}: {
|
||||
input: BigNumber;
|
||||
output: BigNumber;
|
||||
inputAmountPerEth: BigNumber;
|
||||
outputAmountPerEth: BigNumber;
|
||||
ethAmount: BigNumber | number;
|
||||
}): BigNumber {
|
||||
return !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(ethAmount)
|
||||
: inputAmountPerEth.times(ethAmount).times(output.dividedToIntegerBy(input));
|
||||
}
|
||||
|
||||
export function nativeOrdersToFills(
|
||||
side: MarketOperation,
|
||||
orders: NativeOrderWithFillableAmounts[],
|
||||
targetInput: BigNumber = POSITIVE_INF,
|
||||
@@ -89,9 +107,13 @@ function nativeOrdersToFills(
|
||||
const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
|
||||
const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
|
||||
const fee = fees[ERC20BridgeSource.Native] === undefined ? 0 : fees[ERC20BridgeSource.Native]!(o);
|
||||
const outputPenalty = !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(fee)
|
||||
: inputAmountPerEth.times(fee).times(output.dividedToIntegerBy(input));
|
||||
const outputPenalty = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: fee,
|
||||
});
|
||||
// targetInput can be less than the order size
|
||||
// whilst the penalty is constant, it affects the adjusted output
|
||||
// only up until the target has been exhausted.
|
||||
@@ -132,7 +154,7 @@ function nativeOrdersToFills(
|
||||
return fills;
|
||||
}
|
||||
|
||||
function dexSamplesToFills(
|
||||
export function dexSamplesToFills(
|
||||
side: MarketOperation,
|
||||
samples: DexSample[],
|
||||
outputAmountPerEth: BigNumber,
|
||||
@@ -156,9 +178,13 @@ function dexSamplesToFills(
|
||||
let penalty = ZERO_AMOUNT;
|
||||
if (i === 0) {
|
||||
// Only the first fill in a DEX path incurs a penalty.
|
||||
penalty = !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(fee)
|
||||
: inputAmountPerEth.times(fee).times(output.dividedToIntegerBy(input));
|
||||
penalty = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: fee,
|
||||
});
|
||||
}
|
||||
const adjustedOutput = side === MarketOperation.Sell ? output.minus(penalty) : output.plus(penalty);
|
||||
|
||||
|
@@ -39,7 +39,7 @@ import { createFills } from './fills';
|
||||
import { getBestTwoHopQuote } from './multihop_utils';
|
||||
import { createOrdersFromTwoHopSample } from './orders';
|
||||
import { Path, PathPenaltyOpts } from './path';
|
||||
import { fillsToSortedPaths, findOptimalPathAsync } from './path_optimizer';
|
||||
import { fillsToSortedPaths, findOptimalPathJSAsync, findOptimalRustPathFromSamples } from './path_optimizer';
|
||||
import { DexOrderSampler, getSampleAmounts } from './sampler';
|
||||
import { SourceFilters } from './source_filters';
|
||||
import {
|
||||
@@ -48,7 +48,6 @@ import {
|
||||
DexSample,
|
||||
ERC20BridgeSource,
|
||||
Fill,
|
||||
FillData,
|
||||
GenerateOptimizedOrdersOpts,
|
||||
GetMarketOrdersOpts,
|
||||
MarketSideLiquidity,
|
||||
@@ -57,6 +56,8 @@ import {
|
||||
OrderDomain,
|
||||
} from './types';
|
||||
|
||||
const SHOULD_USE_RUST_ROUTER = process.env.RUST_ROUTER === 'true';
|
||||
|
||||
// tslint:disable:boolean-naming
|
||||
|
||||
export class MarketOperationUtils {
|
||||
@@ -326,12 +327,12 @@ export class MarketOperationUtils {
|
||||
public async getBatchMarketBuyOrdersAsync(
|
||||
batchNativeOrders: SignedNativeOrder[][],
|
||||
makerAmounts: BigNumber[],
|
||||
opts?: Partial<GetMarketOrdersOpts>,
|
||||
opts: Partial<GetMarketOrdersOpts> & { gasPrice: BigNumber },
|
||||
): Promise<Array<OptimizerResult | undefined>> {
|
||||
if (batchNativeOrders.length === 0) {
|
||||
throw new Error(AggregationError.EmptyOrders);
|
||||
}
|
||||
const _opts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
|
||||
const _opts: GetMarketOrdersOpts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
|
||||
|
||||
const requestFilters = new SourceFilters().exclude(_opts.excludedSources).include(_opts.includedSources);
|
||||
const quoteSourceFilters = this._buySources.merge(requestFilters);
|
||||
@@ -409,6 +410,7 @@ export class MarketOperationUtils {
|
||||
excludedSources: _opts.excludedSources,
|
||||
feeSchedule: _opts.feeSchedule,
|
||||
allowFallback: _opts.allowFallback,
|
||||
gasPrice: _opts.gasPrice,
|
||||
},
|
||||
);
|
||||
return optimizerResult;
|
||||
@@ -475,6 +477,7 @@ export class MarketOperationUtils {
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
exchangeProxyOverhead: opts.exchangeProxyOverhead || (() => ZERO_AMOUNT),
|
||||
gasPrice: opts.gasPrice,
|
||||
};
|
||||
|
||||
// NOTE: For sell quotes input is the taker asset and for buy quotes input is the maker asset
|
||||
@@ -485,8 +488,22 @@ export class MarketOperationUtils {
|
||||
const _unoptimizedPath = fillsToSortedPaths(fills, side, inputAmount, penaltyOpts)[0];
|
||||
const unoptimizedPath = _unoptimizedPath ? _unoptimizedPath.collapse(orderOpts) : undefined;
|
||||
|
||||
// Find the optimal path
|
||||
const optimalPath = await findOptimalPathAsync(side, fills, inputAmount, opts.runLimit, penaltyOpts);
|
||||
// Find the optimal path using Rust router if enabled, otherwise fallback to JS Router
|
||||
let optimalPath: Path | undefined;
|
||||
if (SHOULD_USE_RUST_ROUTER) {
|
||||
optimalPath = findOptimalRustPathFromSamples(
|
||||
side,
|
||||
dexQuotes,
|
||||
[...nativeOrders, ...augmentedRfqtIndicativeQuotes],
|
||||
inputAmount,
|
||||
penaltyOpts,
|
||||
opts.feeSchedule,
|
||||
this._sampler.chainId,
|
||||
);
|
||||
} else {
|
||||
optimalPath = await findOptimalPathJSAsync(side, fills, inputAmount, opts.runLimit, penaltyOpts);
|
||||
}
|
||||
|
||||
const optimalPathRate = optimalPath ? optimalPath.adjustedRate() : ZERO_AMOUNT;
|
||||
|
||||
const { adjustedRate: bestTwoHopRate, quote: bestTwoHopQuote } = getBestTwoHopQuote(
|
||||
@@ -514,7 +531,7 @@ export class MarketOperationUtils {
|
||||
}
|
||||
|
||||
// Generate a fallback path if required
|
||||
await this._addOptionalFallbackAsync(side, inputAmount, optimalPath, fills, opts, penaltyOpts);
|
||||
await this._addOptionalFallbackAsync(side, inputAmount, optimalPath, dexQuotes, fills, opts, penaltyOpts);
|
||||
const collapsedPath = optimalPath.collapse(orderOpts);
|
||||
|
||||
return {
|
||||
@@ -536,9 +553,9 @@ export class MarketOperationUtils {
|
||||
nativeOrders: SignedNativeOrder[],
|
||||
amount: BigNumber,
|
||||
side: MarketOperation,
|
||||
opts?: Partial<GetMarketOrdersOpts>,
|
||||
opts: Partial<GetMarketOrdersOpts> & { gasPrice: BigNumber },
|
||||
): Promise<OptimizerResultWithReport> {
|
||||
const _opts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
|
||||
const _opts: GetMarketOrdersOpts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
|
||||
const optimizerOpts: GenerateOptimizedOrdersOpts = {
|
||||
bridgeSlippage: _opts.bridgeSlippage,
|
||||
maxFallbackSlippage: _opts.maxFallbackSlippage,
|
||||
@@ -546,6 +563,7 @@ export class MarketOperationUtils {
|
||||
feeSchedule: _opts.feeSchedule,
|
||||
allowFallback: _opts.allowFallback,
|
||||
exchangeProxyOverhead: _opts.exchangeProxyOverhead,
|
||||
gasPrice: _opts.gasPrice,
|
||||
};
|
||||
|
||||
if (nativeOrders.length === 0) {
|
||||
@@ -711,7 +729,8 @@ export class MarketOperationUtils {
|
||||
side: MarketOperation,
|
||||
inputAmount: BigNumber,
|
||||
optimalPath: Path,
|
||||
fills: Array<Array<Fill<FillData>>>,
|
||||
dexQuotes: DexSample[][],
|
||||
fills: Fill[][],
|
||||
opts: GenerateOptimizedOrdersOpts,
|
||||
penaltyOpts: PathPenaltyOpts,
|
||||
): Promise<void> {
|
||||
@@ -725,13 +744,37 @@ export class MarketOperationUtils {
|
||||
if (opts.allowFallback && fragileFills.length !== 0) {
|
||||
// We create a fallback path that is exclusive of Native liquidity
|
||||
// This is the optimal on-chain path for the entire input amount
|
||||
const sturdyFills = fills.filter(p => p.length > 0 && !fragileSources.includes(p[0].source));
|
||||
const sturdyOptimalPath = await findOptimalPathAsync(side, sturdyFills, inputAmount, opts.runLimit, {
|
||||
const sturdyPenaltyOpts = {
|
||||
...penaltyOpts,
|
||||
exchangeProxyOverhead: (sourceFlags: bigint) =>
|
||||
// tslint:disable-next-line: no-bitwise
|
||||
penaltyOpts.exchangeProxyOverhead(sourceFlags | optimalPath.sourceFlags),
|
||||
});
|
||||
};
|
||||
|
||||
let sturdyOptimalPath: Path | undefined;
|
||||
if (SHOULD_USE_RUST_ROUTER) {
|
||||
const sturdySamples = dexQuotes.filter(
|
||||
samples => samples.length > 0 && !fragileSources.includes(samples[0].source),
|
||||
);
|
||||
sturdyOptimalPath = findOptimalRustPathFromSamples(
|
||||
side,
|
||||
sturdySamples,
|
||||
[],
|
||||
inputAmount,
|
||||
sturdyPenaltyOpts,
|
||||
opts.feeSchedule,
|
||||
this._sampler.chainId,
|
||||
);
|
||||
} else {
|
||||
const sturdyFills = fills.filter(p => p.length > 0 && !fragileSources.includes(p[0].source));
|
||||
sturdyOptimalPath = await findOptimalPathJSAsync(
|
||||
side,
|
||||
sturdyFills,
|
||||
inputAmount,
|
||||
opts.runLimit,
|
||||
sturdyPenaltyOpts,
|
||||
);
|
||||
}
|
||||
// Calculate the slippage of on-chain sources compared to the most optimal path
|
||||
// if within an acceptable threshold we enable a fallback to prevent reverts
|
||||
if (
|
||||
|
@@ -3,7 +3,7 @@ import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
import { AssetSwapperContractAddresses, MarketOperation } from '../../types';
|
||||
|
||||
import { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
|
||||
import { MAX_UINT256, ZERO_AMOUNT } from './constants';
|
||||
import {
|
||||
AggregationError,
|
||||
BalancerFillData,
|
||||
@@ -180,8 +180,10 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
||||
return encodeBridgeSourceId(BridgeProtocol.Nerve, 'IronSwap');
|
||||
case ERC20BridgeSource.ACryptos:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Curve, 'ACryptoS');
|
||||
case ERC20BridgeSource.Clipper:
|
||||
return encodeBridgeSourceId(BridgeProtocol.Clipper, 'Clipper');
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Pangolin');
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'TraderJoe');
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@@ -256,6 +258,8 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
case ERC20BridgeSource.Polydex:
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
|
||||
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
|
||||
break;
|
||||
@@ -320,10 +324,6 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
const lidoFillData = (order as OptimizedMarketBridgeOrder<LidoFillData>).fillData;
|
||||
bridgeData = encoder.encode([lidoFillData.stEthTokenAddress]);
|
||||
break;
|
||||
case ERC20BridgeSource.Clipper:
|
||||
const clipperFillData = (order as OptimizedMarketBridgeOrder<LiquidityProviderFillData>).fillData;
|
||||
bridgeData = encoder.encode([clipperFillData.poolAddress, NULL_BYTES]);
|
||||
break;
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@@ -448,6 +448,8 @@ export const BRIDGE_ENCODERS: {
|
||||
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.ShibaSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Pangolin]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.TraderJoe]: routerAddressPathEncoder,
|
||||
// BSC
|
||||
[ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder,
|
||||
@@ -481,10 +483,6 @@ export const BRIDGE_ENCODERS: {
|
||||
]),
|
||||
[ERC20BridgeSource.KyberDmm]: AbiEncoder.create('(address,address[],address[])'),
|
||||
[ERC20BridgeSource.Lido]: AbiEncoder.create('(address)'),
|
||||
[ERC20BridgeSource.Clipper]: AbiEncoder.create([
|
||||
{ name: 'provider', type: 'address' },
|
||||
{ name: 'data', type: 'bytes' },
|
||||
]),
|
||||
};
|
||||
|
||||
function getFillTokenAmounts(fill: CollapsedFill, side: MarketOperation): [BigNumber, BigNumber] {
|
||||
|
@@ -3,6 +3,7 @@ import { BigNumber } from '@0x/utils';
|
||||
import { MarketOperation } from '../../types';
|
||||
|
||||
import { POSITIVE_INF, ZERO_AMOUNT } from './constants';
|
||||
import { ethToOutputAmount } from './fills';
|
||||
import { createBridgeOrder, createNativeOptimizedOrder, CreateOrderFromPathOpts, getMakerTakerTokens } from './orders';
|
||||
import { getCompleteRate, getRate } from './rate_utils';
|
||||
import {
|
||||
@@ -25,12 +26,14 @@ export interface PathPenaltyOpts {
|
||||
outputAmountPerEth: BigNumber;
|
||||
inputAmountPerEth: BigNumber;
|
||||
exchangeProxyOverhead: ExchangeProxyOverhead;
|
||||
gasPrice: BigNumber;
|
||||
}
|
||||
|
||||
export const DEFAULT_PATH_PENALTY_OPTS: PathPenaltyOpts = {
|
||||
outputAmountPerEth: ZERO_AMOUNT,
|
||||
inputAmountPerEth: ZERO_AMOUNT,
|
||||
exchangeProxyOverhead: () => ZERO_AMOUNT,
|
||||
gasPrice: ZERO_AMOUNT,
|
||||
};
|
||||
|
||||
export class Path {
|
||||
@@ -143,9 +146,13 @@ export class Path {
|
||||
const { input, output } = this._adjustedSize;
|
||||
const { exchangeProxyOverhead, outputAmountPerEth, inputAmountPerEth } = this.pathPenaltyOpts;
|
||||
const gasOverhead = exchangeProxyOverhead(this.sourceFlags);
|
||||
const pathPenalty = !outputAmountPerEth.isZero()
|
||||
? outputAmountPerEth.times(gasOverhead)
|
||||
: inputAmountPerEth.times(gasOverhead).times(output.dividedToIntegerBy(input));
|
||||
const pathPenalty = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: gasOverhead,
|
||||
});
|
||||
return {
|
||||
input,
|
||||
output: this.side === MarketOperation.Sell ? output.minus(pathPenalty) : output.plus(pathPenalty),
|
||||
|
@@ -1,20 +1,377 @@
|
||||
import { assert } from '@0x/assert';
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { OptimizerCapture, route, SerializedPath } from '@0x/neon-router';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
import { performance } from 'perf_hooks';
|
||||
|
||||
import { MarketOperation } from '../../types';
|
||||
import { DEFAULT_INFO_LOGGER } from '../../constants';
|
||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../../types';
|
||||
import { VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID } from '../market_operation_utils/constants';
|
||||
|
||||
import { dexSamplesToFills, ethToOutputAmount, nativeOrdersToFills } from './fills';
|
||||
import { DEFAULT_PATH_PENALTY_OPTS, Path, PathPenaltyOpts } from './path';
|
||||
import { ERC20BridgeSource, Fill } from './types';
|
||||
import { getRate } from './rate_utils';
|
||||
import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillData } from './types';
|
||||
|
||||
// tslint:disable: prefer-for-of custom-no-magic-numbers completed-docs no-bitwise
|
||||
|
||||
const RUN_LIMIT_DECAY_FACTOR = 0.5;
|
||||
const RUST_ROUTER_NUM_SAMPLES = 200;
|
||||
const FILL_QUOTE_TRANSFORMER_GAS_OVERHEAD = new BigNumber(150e3);
|
||||
// NOTE: The Rust router will panic with less than 3 samples
|
||||
const MIN_NUM_SAMPLE_INPUTS = 3;
|
||||
|
||||
const isDexSample = (obj: DexSample | NativeOrderWithFillableAmounts): obj is DexSample => !!(obj as DexSample).source;
|
||||
|
||||
function nativeOrderToNormalizedAmounts(
|
||||
side: MarketOperation,
|
||||
nativeOrder: NativeOrderWithFillableAmounts,
|
||||
): { input: BigNumber; output: BigNumber } {
|
||||
const { fillableTakerAmount, fillableTakerFeeAmount, fillableMakerAmount } = nativeOrder;
|
||||
const makerAmount = fillableMakerAmount;
|
||||
const takerAmount = fillableTakerAmount.plus(fillableTakerFeeAmount);
|
||||
const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
|
||||
const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
|
||||
|
||||
return { input, output };
|
||||
}
|
||||
|
||||
function calculateOuputFee(
|
||||
side: MarketOperation,
|
||||
sampleOrNativeOrder: DexSample | NativeOrderWithFillableAmounts,
|
||||
outputAmountPerEth: BigNumber,
|
||||
inputAmountPerEth: BigNumber,
|
||||
fees: FeeSchedule,
|
||||
): BigNumber {
|
||||
if (isDexSample(sampleOrNativeOrder)) {
|
||||
const { input, output, source, fillData } = sampleOrNativeOrder;
|
||||
const fee = fees[source]?.(fillData) || 0;
|
||||
const outputFee = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: fee,
|
||||
});
|
||||
return outputFee;
|
||||
} else {
|
||||
const { input, output } = nativeOrderToNormalizedAmounts(side, sampleOrNativeOrder);
|
||||
const fee = fees[ERC20BridgeSource.Native]?.(sampleOrNativeOrder) || 0;
|
||||
const outputFee = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: fee,
|
||||
});
|
||||
return outputFee;
|
||||
}
|
||||
}
|
||||
|
||||
// Use linear interpolation to approximate the output
|
||||
// at a certain input somewhere between the two samples
|
||||
// See https://en.wikipedia.org/wiki/Linear_interpolation
|
||||
const interpolateOutputFromSamples = (
|
||||
left: { input: BigNumber; output: BigNumber },
|
||||
right: { input: BigNumber; output: BigNumber },
|
||||
targetInput: BigNumber,
|
||||
): BigNumber =>
|
||||
left.output.plus(
|
||||
right.output
|
||||
.minus(left.output)
|
||||
.dividedBy(right.input.minus(left.input))
|
||||
.times(targetInput.minus(left.input)),
|
||||
);
|
||||
|
||||
function findRoutesAndCreateOptimalPath(
|
||||
side: MarketOperation,
|
||||
samples: DexSample[][],
|
||||
nativeOrders: NativeOrderWithFillableAmounts[],
|
||||
input: BigNumber,
|
||||
opts: PathPenaltyOpts,
|
||||
fees: FeeSchedule,
|
||||
): Path | undefined {
|
||||
const createFill = (sample: DexSample) =>
|
||||
dexSamplesToFills(side, [sample], opts.outputAmountPerEth, opts.inputAmountPerEth, fees)[0];
|
||||
// Track sample id's to integers (required by rust router)
|
||||
const sampleIdLookup: { [key: string]: number } = {};
|
||||
let sampleIdCounter = 0;
|
||||
const sampleToId = (source: ERC20BridgeSource, index: number): number => {
|
||||
const key = `${source}-${index}`;
|
||||
if (sampleIdLookup[key]) {
|
||||
return sampleIdLookup[key];
|
||||
} else {
|
||||
sampleIdLookup[key] = ++sampleIdCounter;
|
||||
return sampleIdLookup[key];
|
||||
}
|
||||
};
|
||||
|
||||
const samplesAndNativeOrdersWithResults: Array<DexSample[] | NativeOrderWithFillableAmounts[]> = [];
|
||||
const serializedPaths: SerializedPath[] = [];
|
||||
for (const singleSourceSamples of samples) {
|
||||
if (singleSourceSamples.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const singleSourceSamplesWithOutput = [...singleSourceSamples];
|
||||
for (let i = singleSourceSamples.length - 1; i >= 0; i--) {
|
||||
if (singleSourceSamples[i].output.isZero()) {
|
||||
// Remove trailing 0 output samples
|
||||
singleSourceSamplesWithOutput.pop();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (singleSourceSamplesWithOutput.length < MIN_NUM_SAMPLE_INPUTS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(kimpers): Do we need to handle 0 entries, from eg Kyber?
|
||||
const serializedPath = singleSourceSamplesWithOutput.reduce<SerializedPath>(
|
||||
(memo, sample, sampleIdx) => {
|
||||
memo.ids.push(sampleToId(sample.source, sampleIdx));
|
||||
memo.inputs.push(sample.input.integerValue().toNumber());
|
||||
memo.outputs.push(sample.output.integerValue().toNumber());
|
||||
memo.outputFees.push(
|
||||
calculateOuputFee(side, sample, opts.outputAmountPerEth, opts.inputAmountPerEth, fees)
|
||||
.integerValue()
|
||||
.toNumber(),
|
||||
);
|
||||
|
||||
return memo;
|
||||
},
|
||||
{
|
||||
ids: [],
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
outputFees: [],
|
||||
},
|
||||
);
|
||||
|
||||
samplesAndNativeOrdersWithResults.push(singleSourceSamplesWithOutput);
|
||||
serializedPaths.push(serializedPath);
|
||||
}
|
||||
|
||||
for (const [idx, nativeOrder] of nativeOrders.entries()) {
|
||||
const { input: normalizedOrderInput, output: normalizedOrderOutput } = nativeOrderToNormalizedAmounts(
|
||||
side,
|
||||
nativeOrder,
|
||||
);
|
||||
// NOTE: skip dummy order created in swap_quoter
|
||||
// TODO: remove dummy order and this logic once we don't need the JS router
|
||||
if (normalizedOrderInput.isLessThanOrEqualTo(0) || normalizedOrderOutput.isLessThanOrEqualTo(0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// HACK: the router requires at minimum 3 samples as a basis for interpolation
|
||||
const inputs = [
|
||||
0,
|
||||
normalizedOrderInput
|
||||
.dividedBy(2)
|
||||
.integerValue()
|
||||
.toNumber(),
|
||||
normalizedOrderInput.integerValue().toNumber(),
|
||||
];
|
||||
const outputs = [
|
||||
0,
|
||||
normalizedOrderOutput
|
||||
.dividedBy(2)
|
||||
.integerValue()
|
||||
.toNumber(),
|
||||
normalizedOrderOutput.integerValue().toNumber(),
|
||||
];
|
||||
// NOTE: same fee no matter if full or partial fill
|
||||
const fee = calculateOuputFee(side, nativeOrder, opts.outputAmountPerEth, opts.inputAmountPerEth, fees)
|
||||
.integerValue()
|
||||
.toNumber();
|
||||
const outputFees = [fee, fee, fee];
|
||||
// NOTE: ids can be the same for all fake samples
|
||||
const id = sampleToId(ERC20BridgeSource.Native, idx);
|
||||
const ids = [id, id, id];
|
||||
|
||||
const serializedPath: SerializedPath = {
|
||||
ids,
|
||||
inputs,
|
||||
outputs,
|
||||
outputFees,
|
||||
};
|
||||
|
||||
samplesAndNativeOrdersWithResults.push([nativeOrder]);
|
||||
serializedPaths.push(serializedPath);
|
||||
}
|
||||
|
||||
if (serializedPaths.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const rustArgs: OptimizerCapture = {
|
||||
side,
|
||||
targetInput: input.toNumber(),
|
||||
pathsIn: serializedPaths,
|
||||
};
|
||||
|
||||
const before = performance.now();
|
||||
const allSourcesRustRoute = route(rustArgs, RUST_ROUTER_NUM_SAMPLES);
|
||||
DEFAULT_INFO_LOGGER(
|
||||
{ router: 'neon-router', performanceMs: performance.now() - before, type: 'real' },
|
||||
'Rust router real routing performance',
|
||||
);
|
||||
|
||||
assert.assert(
|
||||
rustArgs.pathsIn.length === allSourcesRustRoute.length,
|
||||
'different number of sources in the Router output than the input',
|
||||
);
|
||||
|
||||
const routesAndSamples = _.zip(allSourcesRustRoute, samplesAndNativeOrdersWithResults);
|
||||
|
||||
const adjustedFills: Fill[] = [];
|
||||
const totalRoutedAmount = BigNumber.sum(...allSourcesRustRoute);
|
||||
|
||||
const scale = input.dividedBy(totalRoutedAmount);
|
||||
for (const [routeInput, routeSamplesAndNativeOrders] of routesAndSamples) {
|
||||
if (!routeInput || !routeSamplesAndNativeOrders) {
|
||||
continue;
|
||||
}
|
||||
// TODO(kimpers): [TKR-241] amounts are sometimes clipped in the router due to precisions loss for number/f64
|
||||
// we can work around it by scaling it and rounding up. However now we end up with a total amount of a couple base units too much
|
||||
const rustInputAdjusted = BigNumber.min(
|
||||
new BigNumber(routeInput).multipliedBy(scale).integerValue(BigNumber.ROUND_CEIL),
|
||||
input,
|
||||
);
|
||||
|
||||
const current = routeSamplesAndNativeOrders[routeSamplesAndNativeOrders.length - 1];
|
||||
if (!isDexSample(current)) {
|
||||
const nativeFill = nativeOrdersToFills(
|
||||
side,
|
||||
[current],
|
||||
rustInputAdjusted,
|
||||
opts.outputAmountPerEth,
|
||||
opts.inputAmountPerEth,
|
||||
fees,
|
||||
)[0];
|
||||
// NOTE: For Limit/RFQ orders we are done here. No need to scale output
|
||||
adjustedFills.push(nativeFill);
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: For DexSamples only
|
||||
let fill = createFill(current);
|
||||
const routeSamples = routeSamplesAndNativeOrders as Array<DexSample<FillData>>;
|
||||
// Descend to approach a closer fill for fillData which may not be consistent
|
||||
// throughout the path (UniswapV3) and for a closer guesstimate at
|
||||
// gas used
|
||||
|
||||
assert.assert(routeSamples.length >= 1, 'Found no sample to use for source');
|
||||
for (let k = routeSamples.length - 1; k >= 0; k--) {
|
||||
if (k === 0) {
|
||||
fill = createFill(routeSamples[0]);
|
||||
}
|
||||
if (rustInputAdjusted.isGreaterThan(routeSamples[k].input)) {
|
||||
// Between here and the previous fill
|
||||
// HACK: Use the midpoint between the two
|
||||
const left = routeSamples[k];
|
||||
const right = routeSamples[k + 1];
|
||||
if (left && right) {
|
||||
// Approximate how much output we get for the input with the surrounding samples
|
||||
const interpolatedOutput = interpolateOutputFromSamples(
|
||||
left,
|
||||
right,
|
||||
rustInputAdjusted,
|
||||
).decimalPlaces(0, side === MarketOperation.Sell ? BigNumber.ROUND_FLOOR : BigNumber.ROUND_CEIL);
|
||||
|
||||
fill = createFill({
|
||||
...right, // default to the greater (for gas used)
|
||||
input: rustInputAdjusted,
|
||||
output: interpolatedOutput,
|
||||
});
|
||||
} else {
|
||||
assert.assert(Boolean(left || right), 'No valid sample to use');
|
||||
fill = createFill(left || right);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const scaleOutput = (output: BigNumber) =>
|
||||
output
|
||||
.dividedBy(fill.input)
|
||||
.times(rustInputAdjusted)
|
||||
.decimalPlaces(0, side === MarketOperation.Sell ? BigNumber.ROUND_FLOOR : BigNumber.ROUND_CEIL);
|
||||
adjustedFills.push({
|
||||
...fill,
|
||||
input: rustInputAdjusted,
|
||||
output: scaleOutput(fill.output),
|
||||
adjustedOutput: scaleOutput(fill.adjustedOutput),
|
||||
index: 0,
|
||||
parent: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
const pathFromRustInputs = Path.create(side, adjustedFills, input);
|
||||
|
||||
return pathFromRustInputs;
|
||||
}
|
||||
|
||||
export function findOptimalRustPathFromSamples(
|
||||
side: MarketOperation,
|
||||
samples: DexSample[][],
|
||||
nativeOrders: NativeOrderWithFillableAmounts[],
|
||||
input: BigNumber,
|
||||
opts: PathPenaltyOpts,
|
||||
fees: FeeSchedule,
|
||||
chainId: ChainId,
|
||||
): Path | undefined {
|
||||
const before = performance.now();
|
||||
const logPerformance = () =>
|
||||
DEFAULT_INFO_LOGGER(
|
||||
{ router: 'neon-router', performanceMs: performance.now() - before, type: 'total' },
|
||||
'Rust router total routing performance',
|
||||
);
|
||||
|
||||
const allSourcesPath = findRoutesAndCreateOptimalPath(side, samples, nativeOrders, input, opts, fees);
|
||||
if (!allSourcesPath) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const vipSources = VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID[chainId];
|
||||
|
||||
// HACK(kimpers): The Rust router currently doesn't account for VIP sources correctly
|
||||
// we need to try to route them in isolation and compare with the results all sources
|
||||
if (vipSources.length > 0) {
|
||||
const vipSourcesSet = new Set(vipSources);
|
||||
const vipSourcesSamples = samples.filter(s => s[0] && vipSourcesSet.has(s[0].source));
|
||||
|
||||
if (vipSourcesSamples.length > 0) {
|
||||
const vipSourcesPath = findRoutesAndCreateOptimalPath(side, vipSourcesSamples, [], input, opts, fees);
|
||||
|
||||
const { input: allSourcesInput, output: allSourcesOutput } = allSourcesPath.adjustedSize();
|
||||
// NOTE: For sell quotes input is the taker asset and for buy quotes input is the maker asset
|
||||
const gasCostInWei = FILL_QUOTE_TRANSFORMER_GAS_OVERHEAD.times(opts.gasPrice);
|
||||
const fqtOverheadInOutputToken = gasCostInWei.times(opts.outputAmountPerEth);
|
||||
const outputWithFqtOverhead =
|
||||
side === MarketOperation.Sell
|
||||
? allSourcesOutput.minus(fqtOverheadInOutputToken)
|
||||
: allSourcesOutput.plus(fqtOverheadInOutputToken);
|
||||
const allSourcesAdjustedRateWithFqtOverhead = getRate(side, allSourcesInput, outputWithFqtOverhead);
|
||||
|
||||
if (vipSourcesPath?.adjustedRate().isGreaterThan(allSourcesAdjustedRateWithFqtOverhead)) {
|
||||
logPerformance();
|
||||
return vipSourcesPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logPerformance();
|
||||
return allSourcesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the optimal mixture of fills that maximizes (for sells) or minimizes
|
||||
* (for buys) output, while meeting the input requirement.
|
||||
*/
|
||||
export async function findOptimalPathAsync(
|
||||
export async function findOptimalPathJSAsync(
|
||||
side: MarketOperation,
|
||||
fills: Fill[][],
|
||||
targetInput: BigNumber,
|
||||
|
@@ -20,7 +20,6 @@ import {
|
||||
import {
|
||||
BALANCER_V2_VAULT_ADDRESS_BY_CHAIN,
|
||||
BANCOR_REGISTRY_BY_CHAIN_ID,
|
||||
CLIPPER_INFO_BY_CHAIN,
|
||||
DODOV1_CONFIG_BY_CHAIN_ID,
|
||||
DODOV2_FACTORIES_BY_CHAIN_ID,
|
||||
KYBER_CONFIG_BY_CHAIN_ID,
|
||||
@@ -1196,6 +1195,8 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.Polydex:
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source);
|
||||
if (!isValidAddress(uniLikeRouter)) {
|
||||
return [];
|
||||
@@ -1414,32 +1415,6 @@ export class SamplerOperations {
|
||||
|
||||
return this.getLidoSellQuotes(lidoInfo, makerToken, takerToken, takerFillAmounts);
|
||||
}
|
||||
case ERC20BridgeSource.Clipper:
|
||||
const { poolAddress: clipperPoolAddress, tokens: clipperTokens } = CLIPPER_INFO_BY_CHAIN[
|
||||
this.chainId
|
||||
];
|
||||
if (
|
||||
clipperPoolAddress === NULL_ADDRESS ||
|
||||
!clipperTokens.includes(makerToken) ||
|
||||
!clipperTokens.includes(takerToken)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
// Clipper requires WETH to be represented as address(0)
|
||||
const adjustedMakerToken =
|
||||
makerToken === NATIVE_FEE_TOKEN_BY_CHAIN_ID[this.chainId] ? NULL_ADDRESS : makerToken;
|
||||
const adjustedTakerToken =
|
||||
takerToken === NATIVE_FEE_TOKEN_BY_CHAIN_ID[this.chainId] ? NULL_ADDRESS : takerToken;
|
||||
// Supports the PLP interface
|
||||
return this.getLiquidityProviderSellQuotes(
|
||||
clipperPoolAddress,
|
||||
adjustedMakerToken,
|
||||
adjustedTakerToken,
|
||||
takerFillAmounts,
|
||||
// tslint:disable-next-line: custom-no-magic-numbers
|
||||
0, // Not used for Clipper
|
||||
ERC20BridgeSource.Clipper,
|
||||
);
|
||||
default:
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
@@ -1489,6 +1464,8 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.Polydex:
|
||||
case ERC20BridgeSource.ShibaSwap:
|
||||
case ERC20BridgeSource.JetSwap:
|
||||
case ERC20BridgeSource.Pangolin:
|
||||
case ERC20BridgeSource.TraderJoe:
|
||||
const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source);
|
||||
if (!isValidAddress(uniLikeRouter)) {
|
||||
return [];
|
||||
@@ -1702,32 +1679,6 @@ export class SamplerOperations {
|
||||
|
||||
return this.getLidoBuyQuotes(lidoInfo, makerToken, takerToken, makerFillAmounts);
|
||||
}
|
||||
case ERC20BridgeSource.Clipper:
|
||||
const { poolAddress: clipperPoolAddress, tokens: clipperTokens } = CLIPPER_INFO_BY_CHAIN[
|
||||
this.chainId
|
||||
];
|
||||
if (
|
||||
clipperPoolAddress === NULL_ADDRESS ||
|
||||
!clipperTokens.includes(makerToken) ||
|
||||
!clipperTokens.includes(takerToken)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
// Clipper requires WETH to be represented as address(0)
|
||||
const adjustedMakerToken =
|
||||
makerToken === NATIVE_FEE_TOKEN_BY_CHAIN_ID[this.chainId] ? NULL_ADDRESS : makerToken;
|
||||
const adjustedTakerToken =
|
||||
takerToken === NATIVE_FEE_TOKEN_BY_CHAIN_ID[this.chainId] ? NULL_ADDRESS : takerToken;
|
||||
// Supports the PLP interface
|
||||
return this.getLiquidityProviderBuyQuotes(
|
||||
clipperPoolAddress,
|
||||
adjustedMakerToken,
|
||||
adjustedTakerToken,
|
||||
makerFillAmounts,
|
||||
// tslint:disable-next-line: custom-no-magic-numbers
|
||||
0, // Not used for Clipper
|
||||
ERC20BridgeSource.Clipper,
|
||||
);
|
||||
default:
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
|
@@ -69,7 +69,6 @@ export enum ERC20BridgeSource {
|
||||
CurveV2 = 'Curve_V2',
|
||||
Lido = 'Lido',
|
||||
ShibaSwap = 'ShibaSwap',
|
||||
Clipper = 'Clipper',
|
||||
// BSC only
|
||||
PancakeSwap = 'PancakeSwap',
|
||||
PancakeSwapV2 = 'PancakeSwap_V2',
|
||||
@@ -91,6 +90,9 @@ export enum ERC20BridgeSource {
|
||||
FirebirdOneSwap = 'FirebirdOneSwap',
|
||||
JetSwap = 'JetSwap',
|
||||
IronSwap = 'IronSwap',
|
||||
// Avalanche
|
||||
Pangolin = 'Pangolin',
|
||||
TraderJoe = 'TraderJoe',
|
||||
}
|
||||
export type SourcesWithPoolsCache = ERC20BridgeSource.Balancer | ERC20BridgeSource.BalancerV2 | ERC20BridgeSource.Cream;
|
||||
|
||||
@@ -452,6 +454,11 @@ export interface GetMarketOrdersOpts {
|
||||
* hopping to. E.g DAI->USDC via an adjacent token WETH
|
||||
*/
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph;
|
||||
|
||||
/**
|
||||
* Gas price to use for quote
|
||||
*/
|
||||
gasPrice: BigNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -531,10 +538,11 @@ export interface GenerateOptimizedOrdersOpts {
|
||||
bridgeSlippage?: number;
|
||||
maxFallbackSlippage?: number;
|
||||
excludedSources?: ERC20BridgeSource[];
|
||||
feeSchedule?: FeeSchedule;
|
||||
feeSchedule: FeeSchedule;
|
||||
exchangeProxyOverhead?: ExchangeProxyOverhead;
|
||||
allowFallback?: boolean;
|
||||
shouldBatchBridgeOrders?: boolean;
|
||||
gasPrice: BigNumber;
|
||||
}
|
||||
|
||||
export interface ComparisonPrice {
|
||||
|
@@ -14,6 +14,7 @@ import { constants } from '../constants';
|
||||
import {
|
||||
AltQuoteModel,
|
||||
AltRfqMakerAssetOfferings,
|
||||
Integrator,
|
||||
LogFunction,
|
||||
MarketOperation,
|
||||
RfqMakerAssetOfferings,
|
||||
@@ -61,6 +62,31 @@ export interface MetricsProxy {
|
||||
* @param expirationTimeSeconds the expiration time in seconds
|
||||
*/
|
||||
incrementFillRatioWarningCounter(isLastLook: boolean, maker: string): void;
|
||||
|
||||
/**
|
||||
* Logs the outcome of a network (HTTP) interaction with a market maker.
|
||||
*
|
||||
* @param interaction.isLastLook true if the request is RFQM
|
||||
* @param interaction.integrator the integrator that is requesting the RFQ quote
|
||||
* @param interaction.url the URL of the market maker
|
||||
* @param interaction.quoteType indicative or firm quote
|
||||
* @param interaction.statusCode the statusCode returned by a market maker
|
||||
* @param interaction.latencyMs the latency of the HTTP request (in ms)
|
||||
* @param interaction.included if a firm quote that was returned got included in the next step of processing.
|
||||
* NOTE: this does not mean that the request returned a valid fillable order. It just
|
||||
* means that the network response was successful.
|
||||
*/
|
||||
logRfqMakerNetworkInteraction(interaction: {
|
||||
isLastLook: boolean;
|
||||
integrator: Integrator;
|
||||
url: string;
|
||||
quoteType: 'firm' | 'indicative';
|
||||
statusCode: number | undefined;
|
||||
latencyMs: number;
|
||||
included: boolean;
|
||||
sellTokenAddress: string;
|
||||
buyTokenAddress: string;
|
||||
}): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,6 +204,42 @@ export class QuoteRequestor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets both standard RFQ makers and "alternative" RFQ makers and combines them together
|
||||
* in a single configuration map. If an integration key whitelist is present, it will be used
|
||||
* to filter a specific makers.
|
||||
*
|
||||
* @param options the RfqmRequestOptions passed in
|
||||
* @param assetOfferings the RFQM or RFQT maker offerings
|
||||
* @returns a list of TypedMakerUrl instances
|
||||
*/
|
||||
public static getTypedMakerUrlsAndWhitelist(
|
||||
options: Pick<RfqmRequestOptions, 'integrator' | 'altRfqAssetOfferings'>,
|
||||
assetOfferings: RfqMakerAssetOfferings,
|
||||
): TypedMakerUrl[] {
|
||||
const standardUrls = Object.keys(assetOfferings).map(
|
||||
(mm: string): TypedMakerUrl => {
|
||||
return { pairType: RfqPairType.Standard, url: mm };
|
||||
},
|
||||
);
|
||||
const altUrls = options.altRfqAssetOfferings
|
||||
? Object.keys(options.altRfqAssetOfferings).map(
|
||||
(mm: string): TypedMakerUrl => {
|
||||
return { pairType: RfqPairType.Alt, url: mm };
|
||||
},
|
||||
)
|
||||
: [];
|
||||
|
||||
let typedMakerUrls = standardUrls.concat(altUrls);
|
||||
|
||||
// If there is a whitelist, only allow approved maker URLs
|
||||
if (options.integrator.whitelistIntegratorUrls !== undefined) {
|
||||
const whitelist = new Set(options.integrator.whitelistIntegratorUrls.map(key => key.toLowerCase()));
|
||||
typedMakerUrls = typedMakerUrls.filter(makerUrl => whitelist.has(makerUrl.url.toLowerCase()));
|
||||
}
|
||||
return typedMakerUrls;
|
||||
}
|
||||
|
||||
public static getDurationUntilExpirationMs(expirationTimeSeconds: BigNumber): BigNumber {
|
||||
const expirationTimeMs = expirationTimeSeconds.times(constants.ONE_SECOND_MS);
|
||||
const currentTimeMs = new BigNumber(Date.now());
|
||||
@@ -401,21 +463,6 @@ export class QuoteRequestor {
|
||||
}
|
||||
})();
|
||||
|
||||
const standardUrls = Object.keys(assetOfferings).map(
|
||||
(mm: string): TypedMakerUrl => {
|
||||
return { pairType: RfqPairType.Standard, url: mm };
|
||||
},
|
||||
);
|
||||
const altUrls = options.altRfqAssetOfferings
|
||||
? Object.keys(options.altRfqAssetOfferings).map(
|
||||
(mm: string): TypedMakerUrl => {
|
||||
return { pairType: RfqPairType.Alt, url: mm };
|
||||
},
|
||||
)
|
||||
: [];
|
||||
|
||||
const typedMakerUrls = standardUrls.concat(altUrls);
|
||||
|
||||
const timeoutMs =
|
||||
options.makerEndpointMaxResponseTimeMs ||
|
||||
constants.DEFAULT_RFQT_REQUEST_OPTS.makerEndpointMaxResponseTimeMs!;
|
||||
@@ -427,11 +474,25 @@ export class QuoteRequestor {
|
||||
cancelTokenSource.cancel('timeout via cancel token');
|
||||
}, timeoutMs + bufferMs);
|
||||
|
||||
const typedMakerUrls = QuoteRequestor.getTypedMakerUrlsAndWhitelist(options, assetOfferings);
|
||||
const quotePromises = typedMakerUrls.map(async typedMakerUrl => {
|
||||
// filter out requests to skip
|
||||
const isBlacklisted = rfqMakerBlacklist.isMakerBlacklisted(typedMakerUrl.url);
|
||||
const partialLogEntry = { url: typedMakerUrl.url, quoteType, requestParams, isBlacklisted };
|
||||
const { isLastLook, integrator } = options;
|
||||
const { sellTokenAddress, buyTokenAddress } = requestParams;
|
||||
if (isBlacklisted) {
|
||||
this._metrics?.logRfqMakerNetworkInteraction({
|
||||
isLastLook: false,
|
||||
url: typedMakerUrl.url,
|
||||
quoteType,
|
||||
statusCode: undefined,
|
||||
sellTokenAddress,
|
||||
buyTokenAddress,
|
||||
latencyMs: 0,
|
||||
included: false,
|
||||
integrator,
|
||||
});
|
||||
this._infoLogger({ rfqtMakerInteraction: { ...partialLogEntry } });
|
||||
return;
|
||||
} else if (
|
||||
@@ -450,18 +511,32 @@ export class QuoteRequestor {
|
||||
try {
|
||||
if (typedMakerUrl.pairType === RfqPairType.Standard) {
|
||||
const response = await this._quoteRequestorHttpClient.get(`${typedMakerUrl.url}/${quotePath}`, {
|
||||
headers: { '0x-api-key': options.apiKey },
|
||||
headers: {
|
||||
'0x-api-key': options.integrator.integratorId,
|
||||
'0x-integrator-id': options.integrator.integratorId,
|
||||
},
|
||||
params: requestParams,
|
||||
timeout: timeoutMs,
|
||||
cancelToken: cancelTokenSource.token,
|
||||
});
|
||||
const latencyMs = Date.now() - timeBeforeAwait;
|
||||
this._metrics?.logRfqMakerNetworkInteraction({
|
||||
isLastLook: isLastLook || false,
|
||||
url: typedMakerUrl.url,
|
||||
quoteType,
|
||||
statusCode: response.status,
|
||||
sellTokenAddress,
|
||||
buyTokenAddress,
|
||||
latencyMs,
|
||||
included: true,
|
||||
integrator,
|
||||
});
|
||||
this._infoLogger({
|
||||
rfqtMakerInteraction: {
|
||||
...partialLogEntry,
|
||||
response: {
|
||||
included: true,
|
||||
apiKey: options.apiKey,
|
||||
apiKey: options.integrator.integratorId,
|
||||
takerAddress: requestParams.takerAddress,
|
||||
txOrigin: requestParams.txOrigin,
|
||||
statusCode: response.status,
|
||||
@@ -479,7 +554,7 @@ export class QuoteRequestor {
|
||||
typedMakerUrl.url,
|
||||
this._altRfqCreds.altRfqApiKey,
|
||||
this._altRfqCreds.altRfqProfile,
|
||||
options.apiKey,
|
||||
options.integrator.integratorId,
|
||||
quoteType === 'firm' ? AltQuoteModel.Firm : AltQuoteModel.Indicative,
|
||||
makerToken,
|
||||
takerToken,
|
||||
@@ -492,12 +567,23 @@ export class QuoteRequestor {
|
||||
);
|
||||
|
||||
const latencyMs = Date.now() - timeBeforeAwait;
|
||||
this._metrics?.logRfqMakerNetworkInteraction({
|
||||
isLastLook: isLastLook || false,
|
||||
url: typedMakerUrl.url,
|
||||
quoteType,
|
||||
statusCode: quote.status,
|
||||
sellTokenAddress,
|
||||
buyTokenAddress,
|
||||
latencyMs,
|
||||
included: true,
|
||||
integrator,
|
||||
});
|
||||
this._infoLogger({
|
||||
rfqtMakerInteraction: {
|
||||
...partialLogEntry,
|
||||
response: {
|
||||
included: true,
|
||||
apiKey: options.apiKey,
|
||||
apiKey: options.integrator.integratorId,
|
||||
takerAddress: requestParams.takerAddress,
|
||||
txOrigin: requestParams.txOrigin,
|
||||
statusCode: quote.status,
|
||||
@@ -511,12 +597,23 @@ export class QuoteRequestor {
|
||||
} catch (err) {
|
||||
// log error if any
|
||||
const latencyMs = Date.now() - timeBeforeAwait;
|
||||
this._metrics?.logRfqMakerNetworkInteraction({
|
||||
isLastLook: isLastLook || false,
|
||||
url: typedMakerUrl.url,
|
||||
quoteType,
|
||||
statusCode: err.response?.status,
|
||||
sellTokenAddress,
|
||||
buyTokenAddress,
|
||||
latencyMs,
|
||||
included: false,
|
||||
integrator,
|
||||
});
|
||||
this._infoLogger({
|
||||
rfqtMakerInteraction: {
|
||||
...partialLogEntry,
|
||||
response: {
|
||||
included: false,
|
||||
apiKey: options.apiKey,
|
||||
apiKey: options.integrator.integratorId,
|
||||
takerAddress: requestParams.takerAddress,
|
||||
txOrigin: requestParams.txOrigin,
|
||||
statusCode: err.response ? err.response.status : undefined,
|
||||
@@ -527,7 +624,7 @@ export class QuoteRequestor {
|
||||
rfqMakerBlacklist.logTimeoutOrLackThereof(typedMakerUrl.url, latencyMs >= timeoutMs);
|
||||
this._warningLogger(
|
||||
convertIfAxiosError(err),
|
||||
`Failed to get RFQ-T ${quoteType} quote from market maker endpoint ${typedMakerUrl.url} for API key ${options.apiKey} for taker address ${options.takerAddress} and tx origin ${options.txOrigin}`,
|
||||
`Failed to get RFQ-T ${quoteType} quote from market maker endpoint ${typedMakerUrl.url} for integrator ${options.integrator.integratorId} (${options.integrator.label}) for taker address ${options.takerAddress} and tx origin ${options.txOrigin}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@@ -28,7 +28,11 @@ export const rfqtMocker = {
|
||||
// Mock out RFQT responses
|
||||
for (const mockedResponse of mockedResponses) {
|
||||
const { endpoint, requestApiKey, requestParams, responseData, responseCode } = mockedResponse;
|
||||
const requestHeaders = { Accept: 'application/json, text/plain, */*', '0x-api-key': requestApiKey };
|
||||
const requestHeaders = {
|
||||
Accept: 'application/json, text/plain, */*',
|
||||
'0x-api-key': requestApiKey,
|
||||
'0x-integrator-id': requestApiKey,
|
||||
};
|
||||
mockedAxios
|
||||
.onGet(`${endpoint}/${quoteType}`, { params: requestParams }, requestHeaders)
|
||||
.replyOnce(responseCode, responseData);
|
||||
|
@@ -18,7 +18,9 @@ import { DummyLiquidityProviderContract, TestERC20BridgeSamplerContract } from '
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
const { NULL_ADDRESS } = constants;
|
||||
blockchainTests('erc20-bridge-sampler', env => {
|
||||
// HACK(dorothy-zbornak): Disabled because these tests are flakey and all this logic is moving to
|
||||
// the sampler service anyway.
|
||||
blockchainTests.skip('erc20-bridge-sampler', env => {
|
||||
let testContract: TestERC20BridgeSamplerContract;
|
||||
const RATE_DENOMINATOR = constants.ONE_ETHER;
|
||||
const MIN_RATE = new BigNumber('0.01');
|
||||
|
@@ -186,7 +186,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
);
|
||||
}
|
||||
|
||||
const transformERC20Encoder = AbiEncoder.createMethod('transformERC20', [
|
||||
const transformERC20Encoder = AbiEncoder.createMethod('transformERC20Staging', [
|
||||
{ type: 'address', name: 'inputToken' },
|
||||
{ type: 'address', name: 'outputToken' },
|
||||
{ type: 'uint256', name: 'inputTokenAmount' },
|
||||
@@ -261,7 +261,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
|
||||
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
|
||||
expect(payTakerTransformerData.amounts).to.deep.eq([]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
});
|
||||
|
||||
it('can produce a buy quote', async () => {
|
||||
@@ -292,7 +292,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
|
||||
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
|
||||
expect(payTakerTransformerData.amounts).to.deep.eq([]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
});
|
||||
|
||||
it('ERC20 -> ERC20 does not have a WETH transformer', async () => {
|
||||
@@ -437,12 +437,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
expect(secondHopFillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
|
||||
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[2].data);
|
||||
expect(payTakerTransformerData.amounts).to.deep.eq([]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
INTERMEDIATE_TOKEN,
|
||||
]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, INTERMEDIATE_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
});
|
||||
// it.skip('Uses the `LiquidityProviderFeature` if given a single LiquidityProvider order', async () => {
|
||||
// const quote = {
|
||||
@@ -504,7 +499,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
|
||||
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
|
||||
expect(payTakerTransformerData.amounts).to.deep.eq([]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -16,7 +16,7 @@ import * as _ from 'lodash';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
|
||||
import { MarketOperation, QuoteRequestor, RfqRequestOpts, SignedNativeOrder } from '../src';
|
||||
import { NativeOrderWithFillableAmounts } from '../src/types';
|
||||
import { Integrator, NativeOrderWithFillableAmounts } from '../src/types';
|
||||
import { MarketOperationUtils } from '../src/utils/market_operation_utils/';
|
||||
import {
|
||||
BUY_SOURCE_FILTER_BY_CHAIN_ID,
|
||||
@@ -62,6 +62,10 @@ const SELL_SOURCES = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
|
||||
const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = { default: [] };
|
||||
|
||||
const SIGNATURE = { v: 1, r: NULL_BYTES, s: NULL_BYTES, signatureType: SignatureType.EthSign };
|
||||
const FOO_INTEGRATOR: Integrator = {
|
||||
integratorId: 'foo',
|
||||
label: 'foo',
|
||||
};
|
||||
|
||||
/**
|
||||
* gets the orders required for a market sell operation by (potentially) merging native orders with
|
||||
@@ -75,7 +79,7 @@ async function getMarketSellOrdersAsync(
|
||||
utils: MarketOperationUtils,
|
||||
nativeOrders: SignedNativeOrder[],
|
||||
takerAmount: BigNumber,
|
||||
opts?: Partial<GetMarketOrdersOpts>,
|
||||
opts: Partial<GetMarketOrdersOpts> & { gasPrice: BigNumber },
|
||||
): Promise<OptimizerResultWithReport> {
|
||||
return utils.getOptimizerResultAsync(nativeOrders, takerAmount, MarketOperation.Sell, opts);
|
||||
}
|
||||
@@ -92,7 +96,7 @@ async function getMarketBuyOrdersAsync(
|
||||
utils: MarketOperationUtils,
|
||||
nativeOrders: SignedNativeOrder[],
|
||||
makerAmount: BigNumber,
|
||||
opts?: Partial<GetMarketOrdersOpts>,
|
||||
opts: Partial<GetMarketOrdersOpts> & { gasPrice: BigNumber },
|
||||
): Promise<OptimizerResultWithReport> {
|
||||
return utils.getOptimizerResultAsync(nativeOrders, makerAmount, MarketOperation.Buy, opts);
|
||||
}
|
||||
@@ -455,7 +459,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
FILL_AMOUNT,
|
||||
_.times(NUM_SAMPLES, i => DEFAULT_RATES[ERC20BridgeSource.Native][i]),
|
||||
);
|
||||
const DEFAULT_OPTS: Partial<GetMarketOrdersOpts> = {
|
||||
const DEFAULT_OPTS: Partial<GetMarketOrdersOpts> & { gasPrice: BigNumber } = {
|
||||
numSamples: NUM_SAMPLES,
|
||||
sampleDistributionBase: 1,
|
||||
bridgeSlippage: 0,
|
||||
@@ -464,6 +468,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
allowFallback: false,
|
||||
gasSchedule: {},
|
||||
feeSchedule: {},
|
||||
gasPrice: new BigNumber(30e9),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -745,7 +750,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
feeSchedule,
|
||||
rfqt: {
|
||||
isIndicative: false,
|
||||
apiKey: 'foo',
|
||||
integrator: FOO_INTEGRATOR,
|
||||
takerAddress: randomAddress(),
|
||||
txOrigin: randomAddress(),
|
||||
intentOnFilling: true,
|
||||
@@ -790,7 +795,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
rfqt: {
|
||||
isIndicative: false,
|
||||
apiKey: 'foo',
|
||||
integrator: FOO_INTEGRATOR,
|
||||
takerAddress: randomAddress(),
|
||||
intentOnFilling: true,
|
||||
txOrigin: randomAddress(),
|
||||
@@ -837,7 +842,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
rfqt: {
|
||||
isIndicative: true,
|
||||
apiKey: 'foo',
|
||||
integrator: FOO_INTEGRATOR,
|
||||
takerAddress: randomAddress(),
|
||||
txOrigin: randomAddress(),
|
||||
intentOnFilling: true,
|
||||
@@ -896,7 +901,10 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
rfqt: {
|
||||
isIndicative: false,
|
||||
apiKey: 'foo',
|
||||
integrator: {
|
||||
integratorId: 'foo',
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress: randomAddress(),
|
||||
intentOnFilling: true,
|
||||
txOrigin: randomAddress(),
|
||||
@@ -954,7 +962,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
rfqt: {
|
||||
isIndicative: false,
|
||||
apiKey: 'foo',
|
||||
integrator: FOO_INTEGRATOR,
|
||||
takerAddress: randomAddress(),
|
||||
txOrigin: randomAddress(),
|
||||
intentOnFilling: true,
|
||||
@@ -1222,6 +1230,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
excludedSources: [],
|
||||
numSamples: 4,
|
||||
bridgeSlippage: 0,
|
||||
gasPrice: new BigNumber(30e9),
|
||||
},
|
||||
);
|
||||
const result = ordersAndReport.optimizedOrders;
|
||||
@@ -1291,7 +1300,8 @@ describe('MarketOperationUtils tests', () => {
|
||||
FILL_AMOUNT,
|
||||
_.times(NUM_SAMPLES, () => DEFAULT_RATES[ERC20BridgeSource.Native][0]),
|
||||
);
|
||||
const DEFAULT_OPTS: Partial<GetMarketOrdersOpts> = {
|
||||
const GAS_PRICE = new BigNumber(100e9); // 100 gwei
|
||||
const DEFAULT_OPTS: Partial<GetMarketOrdersOpts> & { gasPrice: BigNumber } = {
|
||||
numSamples: NUM_SAMPLES,
|
||||
sampleDistributionBase: 1,
|
||||
bridgeSlippage: 0,
|
||||
@@ -1300,6 +1310,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
allowFallback: false,
|
||||
gasSchedule: {},
|
||||
feeSchedule: {},
|
||||
gasPrice: GAS_PRICE,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -1619,11 +1630,10 @@ describe('MarketOperationUtils tests', () => {
|
||||
getMedianSellRate: createGetMedianSellRate(ETH_TO_TAKER_RATE),
|
||||
});
|
||||
const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||
const gasPrice = 100e9; // 100 gwei
|
||||
const exchangeProxyOverhead = (sourceFlags: bigint) =>
|
||||
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
||||
? constants.ZERO_AMOUNT
|
||||
: new BigNumber(1.3e5).times(gasPrice);
|
||||
: new BigNumber(1.3e5).times(GAS_PRICE);
|
||||
const improvedOrdersResponse = await optimizer.getOptimizerResultAsync(
|
||||
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
||||
FILL_AMOUNT,
|
||||
|
@@ -240,7 +240,10 @@ describe('QuoteRequestor', async () => {
|
||||
MarketOperation.Sell,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin: takerAddress,
|
||||
intentOnFilling: true,
|
||||
@@ -435,7 +438,10 @@ describe('QuoteRequestor', async () => {
|
||||
MarketOperation.Sell,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin: takerAddress,
|
||||
intentOnFilling: true,
|
||||
@@ -551,7 +557,10 @@ describe('QuoteRequestor', async () => {
|
||||
MarketOperation.Sell,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin: takerAddress,
|
||||
intentOnFilling: true,
|
||||
@@ -675,7 +684,10 @@ describe('QuoteRequestor', async () => {
|
||||
MarketOperation.Sell,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin: takerAddress,
|
||||
intentOnFilling: true,
|
||||
@@ -762,7 +774,10 @@ describe('QuoteRequestor', async () => {
|
||||
MarketOperation.Sell,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin: takerAddress,
|
||||
intentOnFilling: true,
|
||||
@@ -823,7 +838,10 @@ describe('QuoteRequestor', async () => {
|
||||
MarketOperation.Buy,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin: takerAddress,
|
||||
intentOnFilling: true,
|
||||
@@ -834,6 +852,43 @@ describe('QuoteRequestor', async () => {
|
||||
quoteRequestorHttpClient,
|
||||
);
|
||||
});
|
||||
it('should be able to handle and filter RFQ offerings', () => {
|
||||
const tests: Array<[string[] | undefined, string[]]> = [
|
||||
[['https://top.maker'], []],
|
||||
[undefined, ['https://foo.bar/', 'https://lorem.ipsum/']],
|
||||
[['https://lorem.ipsum/'], ['https://lorem.ipsum/']],
|
||||
];
|
||||
for (const test of tests) {
|
||||
const [apiKeyWhitelist, results] = test;
|
||||
const response = QuoteRequestor.getTypedMakerUrlsAndWhitelist(
|
||||
{
|
||||
integrator: {
|
||||
integratorId: 'foo',
|
||||
label: 'bar',
|
||||
whitelistIntegratorUrls: apiKeyWhitelist,
|
||||
},
|
||||
altRfqAssetOfferings: {},
|
||||
},
|
||||
{
|
||||
'https://foo.bar/': [
|
||||
[
|
||||
'0xA6cD4cb8c62aCDe44739E3Ed0F1d13E0e31f2d94',
|
||||
'0xF45107c0200a04A8aB9C600cc52A3C89AE5D0489',
|
||||
],
|
||||
],
|
||||
'https://lorem.ipsum/': [
|
||||
[
|
||||
'0xA6cD4cb8c62aCDe44739E3Ed0F1d13E0e31f2d94',
|
||||
'0xF45107c0200a04A8aB9C600cc52A3C89AE5D0489',
|
||||
],
|
||||
],
|
||||
},
|
||||
);
|
||||
const typedUrls = response.map(typed => typed.url);
|
||||
expect(typedUrls).to.eql(results);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return successful alt indicative quotes', async () => {
|
||||
const takerAddress = '0xd209925defc99488e3afff1174e48b4fa628302a';
|
||||
const txOrigin = '0xf209925defc99488e3afff1174e48b4fa628302a';
|
||||
@@ -1055,7 +1110,10 @@ describe('QuoteRequestor', async () => {
|
||||
altScenario.requestedOperation,
|
||||
undefined,
|
||||
{
|
||||
apiKey,
|
||||
integrator: {
|
||||
integratorId: apiKey,
|
||||
label: 'foo',
|
||||
},
|
||||
takerAddress,
|
||||
txOrigin,
|
||||
intentOnFilling: true,
|
||||
|
@@ -744,7 +744,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: fillableInput,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
if (side === MarketOperation.Sell) {
|
||||
expect(result.totalMakerAssetAmount).to.be.bignumber.eq(fillableOutput);
|
||||
@@ -769,10 +769,10 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: fillableInput,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
expect(result.gas).to.eq(countCollapsedFills(orders));
|
||||
expect(result.protocolFeeAmount).to.bignumber.gt(orders.length);
|
||||
expect(result.protocolFeeAmount).to.bignumber.eq(orders.length);
|
||||
expect(result.takerFeeTakerAssetAmount).to.bignumber.eq(0);
|
||||
expect(result.takerFeeMakerAssetAmount).to.bignumber.eq(0);
|
||||
expect(result.makerAssetAmount).to.bignumber.eq(result.totalMakerAssetAmount);
|
||||
@@ -801,7 +801,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: inputFillAmount,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
expect(result.gas).to.gt(0);
|
||||
expect(result.protocolFeeAmount).to.bignumber.gt(0);
|
||||
@@ -835,7 +835,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: totalFillableInput,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
|
||||
assertRoughlyEquals(result.takerAssetAmount, fillableInput);
|
||||
@@ -865,7 +865,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: inputFillAmount,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
expect(result.gas).to.gt(0);
|
||||
expect(result.protocolFeeAmount).to.bignumber.gt(0);
|
||||
@@ -893,10 +893,10 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: fillableInput,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
expect(result.gas).to.eq(countCollapsedFills(orders));
|
||||
expect(result.protocolFeeAmount).to.bignumber.gt(orders.length);
|
||||
expect(result.protocolFeeAmount).to.bignumber.eq(orders.length);
|
||||
|
||||
assertRoughlyEquals(result.makerAssetAmount, fillableInput);
|
||||
assertRoughlyEquals(result.totalMakerAssetAmount, fillableInput);
|
||||
@@ -923,7 +923,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: inputFillAmount,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
expect(result.gas).to.gt(0);
|
||||
expect(result.protocolFeeAmount).to.bignumber.gt(0);
|
||||
@@ -951,7 +951,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: fillableInput,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE, slippage },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE, slippage },
|
||||
});
|
||||
if (side === MarketOperation.Sell) {
|
||||
const slippedOutput = fillableOutput.times(1 - slippage).integerValue();
|
||||
@@ -982,7 +982,7 @@ describe('quote_simulation tests', async () => {
|
||||
side,
|
||||
fillAmount: fillableInput,
|
||||
gasPrice: ONE,
|
||||
opts: { gasSchedule: GAS_SCHEDULE },
|
||||
opts: { gasSchedule: GAS_SCHEDULE, protocolFeeMultiplier: ONE },
|
||||
});
|
||||
const worstCase = simulateWorstCaseFill({
|
||||
orders,
|
||||
|
@@ -48,7 +48,11 @@ export const testHelpers = {
|
||||
// Mock out Standard RFQ-T/M responses
|
||||
for (const mockedResponse of standardMockedResponses) {
|
||||
const { endpoint, requestApiKey, requestParams, responseData, responseCode } = mockedResponse;
|
||||
const requestHeaders = { Accept: 'application/json, text/plain, */*', '0x-api-key': requestApiKey };
|
||||
const requestHeaders = {
|
||||
Accept: 'application/json, text/plain, */*',
|
||||
'0x-api-key': requestApiKey,
|
||||
'0x-integrator-id': requestApiKey,
|
||||
};
|
||||
if (mockedResponse.callback !== undefined) {
|
||||
mockedAxios
|
||||
.onGet(`${endpoint}/${quoteType}`, { params: requestParams }, requestHeaders)
|
||||
|
@@ -1,4 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "6.7.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Avalanche deployment",
|
||||
"pr": 312
|
||||
}
|
||||
],
|
||||
"timestamp": 1630459879
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "6.6.1",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.7.0 - _September 1, 2021_
|
||||
|
||||
* Avalanche deployment (#312)
|
||||
|
||||
## v6.6.1 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -334,5 +334,47 @@
|
||||
"fillQuoteTransformer": "0x750cb81ee6d64e29e1e358ba155925000bf044d4",
|
||||
"positiveSlippageFeeTransformer": "0x30aebc4c68effa70e21612b39b94299a8778d0cb"
|
||||
}
|
||||
},
|
||||
"43114": {
|
||||
"erc20Proxy": "0x0000000000000000000000000000000000000000",
|
||||
"erc721Proxy": "0x0000000000000000000000000000000000000000",
|
||||
"zrxToken": "0x0000000000000000000000000000000000000000",
|
||||
"etherToken": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
|
||||
"exchangeV2": "0x0000000000000000000000000000000000000000",
|
||||
"exchange": "0x0000000000000000000000000000000000000000",
|
||||
"assetProxyOwner": "0x0000000000000000000000000000000000000000",
|
||||
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
|
||||
"forwarder": "0x0000000000000000000000000000000000000000",
|
||||
"coordinatorRegistry": "0x0000000000000000000000000000000000000000",
|
||||
"coordinator": "0x0000000000000000000000000000000000000000",
|
||||
"multiAssetProxy": "0x0000000000000000000000000000000000000000",
|
||||
"staticCallProxy": "0x0000000000000000000000000000000000000000",
|
||||
"erc1155Proxy": "0x0000000000000000000000000000000000000000",
|
||||
"devUtils": "0x0000000000000000000000000000000000000000",
|
||||
"zrxVault": "0x0000000000000000000000000000000000000000",
|
||||
"staking": "0x0000000000000000000000000000000000000000",
|
||||
"stakingProxy": "0x0000000000000000000000000000000000000000",
|
||||
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
|
||||
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
|
||||
"chaiBridge": "0x0000000000000000000000000000000000000000",
|
||||
"dydxBridge": "0x0000000000000000000000000000000000000000",
|
||||
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
|
||||
"broker": "0x0000000000000000000000000000000000000000",
|
||||
"chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
|
||||
"maximumGasPrice": "0x0000000000000000000000000000000000000000",
|
||||
"dexForwarderBridge": "0x0000000000000000000000000000000000000000",
|
||||
"exchangeProxyGovernor": "0xca7bab1b2d1ec7d81710b7f9e2ab4e6788930588",
|
||||
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"exchangeProxyTransformerDeployer": "0xa60b57833dce6260f4f2411c811755dd980bc0a7",
|
||||
"exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
|
||||
"exchangeProxyLiquidityProviderSandbox": "0x8953c63d0858d286cc407cd6f8e26b9cbd02a511",
|
||||
"zrxTreasury": "0x0000000000000000000000000000000000000000",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
|
||||
"payTakerTransformer": "0x898c6fde239d646c73f0a57e3570b6f86a3d62a3",
|
||||
"affiliateFeeTransformer": "0x34617b855411e52fbc05899435f44cbd0503022c",
|
||||
"fillQuoteTransformer": "0x8a5417dd7ffde61ec61e11b45797e16686e1d6b9",
|
||||
"positiveSlippageFeeTransformer": "0x470ba89da18a6db6e8a0567b3c9214b960861857"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contract-addresses",
|
||||
"version": "6.6.1",
|
||||
"version": "6.7.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
|
@@ -52,6 +52,7 @@ export enum ChainId {
|
||||
BSC = 56,
|
||||
Polygon = 137,
|
||||
PolygonMumbai = 80001,
|
||||
Avalanche = 43114,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"version": "3.16.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update IZeroEx and ITransformERC20 artifacts",
|
||||
"pr": 282
|
||||
}
|
||||
],
|
||||
"timestamp": 1632957537
|
||||
},
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "3.15.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.15.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.16.0 - _September 29, 2021_
|
||||
|
||||
* Update IZeroEx and ITransformERC20 artifacts (#282)
|
||||
|
||||
## v3.15.1 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.15.0 - _June 2, 2021_
|
||||
|
||||
* Update artifacts (#237)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": "2.0.0",
|
||||
"contractName": "ITransformERC20",
|
||||
"contractName": "ITransformERC20Feature",
|
||||
"compilerOutput": {
|
||||
"abi": [
|
||||
{
|
||||
@@ -43,14 +43,14 @@
|
||||
{ "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct ITransformERC20.Transformation[]",
|
||||
"internalType": "struct ITransformERC20Feature.Transformation[]",
|
||||
"name": "transformations",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "bytes32", "name": "callDataHash", "type": "bytes32" },
|
||||
{ "internalType": "bytes", "name": "callDataSignature", "type": "bytes" }
|
||||
{ "internalType": "bool", "name": "useSelfBalance", "type": "bool" },
|
||||
{ "internalType": "address payable", "name": "recipient", "type": "address" }
|
||||
],
|
||||
"internalType": "struct ITransformERC20.TransformERC20Args",
|
||||
"internalType": "struct ITransformERC20Feature.TransformERC20Args",
|
||||
"name": "args",
|
||||
"type": "tuple"
|
||||
}
|
||||
@@ -113,7 +113,7 @@
|
||||
{ "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct ITransformERC20.Transformation[]",
|
||||
"internalType": "struct ITransformERC20Feature.Transformation[]",
|
||||
"name": "transformations",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
@@ -148,7 +148,7 @@
|
||||
},
|
||||
"kind": "dev",
|
||||
"methods": {
|
||||
"_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bytes32,bytes))": {
|
||||
"_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))": {
|
||||
"details": "Internal version of `transformERC20()`. Only callable from within.",
|
||||
"params": { "args": "A `TransformERC20Args` struct." },
|
||||
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." }
|
||||
@@ -212,7 +212,8 @@
|
||||
"evm.bytecode.object",
|
||||
"evm.bytecode.sourceMap",
|
||||
"evm.deployedBytecode.object",
|
||||
"evm.deployedBytecode.sourceMap"
|
||||
"evm.deployedBytecode.sourceMap",
|
||||
"evm.methodIdentifiers"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@@ -3,16 +3,6 @@
|
||||
"contractName": "IZeroEx",
|
||||
"compilerOutput": {
|
||||
"abi": [
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "bytes32", "name": "orderHash", "type": "bytes32" },
|
||||
{ "indexed": false, "internalType": "address", "name": "maker", "type": "address" },
|
||||
{ "indexed": false, "internalType": "uint64", "name": "expiry", "type": "uint64" }
|
||||
],
|
||||
"name": "ExpiredRfqOrder",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
@@ -49,11 +39,26 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "address", "name": "inputToken", "type": "address" },
|
||||
{ "indexed": false, "internalType": "address", "name": "outputToken", "type": "address" },
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract IERC20TokenV06",
|
||||
"name": "inputToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract IERC20TokenV06",
|
||||
"name": "outputToken",
|
||||
"type": "address"
|
||||
},
|
||||
{ "indexed": false, "internalType": "uint256", "name": "inputTokenAmount", "type": "uint256" },
|
||||
{ "indexed": false, "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" },
|
||||
{ "indexed": false, "internalType": "address", "name": "provider", "type": "address" },
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract ILiquidityProvider",
|
||||
"name": "provider",
|
||||
"type": "address"
|
||||
},
|
||||
{ "indexed": false, "internalType": "address", "name": "recipient", "type": "address" }
|
||||
],
|
||||
"name": "LiquidityProviderSwap",
|
||||
@@ -110,10 +115,10 @@
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "takerTokenFilledAmount",
|
||||
"name": "makerTokenFilledAmount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{ "indexed": false, "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
|
||||
{ "indexed": false, "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" }
|
||||
],
|
||||
"name": "OtcOrderFilled",
|
||||
"type": "event"
|
||||
@@ -268,6 +273,51 @@
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" },
|
||||
{ "internalType": "uint128", "name": "makerAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "takerAmount", "type": "uint128" },
|
||||
{ "internalType": "address", "name": "maker", "type": "address" },
|
||||
{ "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "internalType": "address", "name": "txOrigin", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" }
|
||||
],
|
||||
"internalType": "struct LibNativeOrder.OtcOrder",
|
||||
"name": "order",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum LibSignature.SignatureType",
|
||||
"name": "signatureType",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint8", "name": "v", "type": "uint8" },
|
||||
{ "internalType": "bytes32", "name": "r", "type": "bytes32" },
|
||||
{ "internalType": "bytes32", "name": "s", "type": "bytes32" }
|
||||
],
|
||||
"internalType": "struct LibSignature.Signature",
|
||||
"name": "makerSignature",
|
||||
"type": "tuple"
|
||||
},
|
||||
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" },
|
||||
{ "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "internalType": "bool", "name": "useSelfBalance", "type": "bool" },
|
||||
{ "internalType": "address", "name": "recipient", "type": "address" }
|
||||
],
|
||||
"name": "_fillOtcOrder",
|
||||
"outputs": [
|
||||
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@@ -303,7 +353,9 @@
|
||||
"type": "tuple"
|
||||
},
|
||||
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" },
|
||||
{ "internalType": "address", "name": "taker", "type": "address" }
|
||||
{ "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "internalType": "bool", "name": "useSelfBalance", "type": "bool" },
|
||||
{ "internalType": "address", "name": "recipient", "type": "address" }
|
||||
],
|
||||
"name": "_fillRfqOrder",
|
||||
"outputs": [
|
||||
@@ -313,6 +365,18 @@
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "bytes", "name": "encodedPath", "type": "bytes" },
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" },
|
||||
{ "internalType": "address", "name": "recipient", "type": "address" }
|
||||
],
|
||||
"name": "_sellHeldTokenForTokenToUniswapV3",
|
||||
"outputs": [{ "internalType": "uint256", "name": "buyAmount", "type": "uint256" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@@ -330,7 +394,9 @@
|
||||
"internalType": "struct ITransformERC20Feature.Transformation[]",
|
||||
"name": "transformations",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
},
|
||||
{ "internalType": "bool", "name": "useSelfBalance", "type": "bool" },
|
||||
{ "internalType": "address payable", "name": "recipient", "type": "address" }
|
||||
],
|
||||
"internalType": "struct ITransformERC20Feature.TransformERC20Args",
|
||||
"name": "args",
|
||||
@@ -480,35 +546,6 @@
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "bytes4", "name": "selector", "type": "bytes4" },
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.WrappedBatchCall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.BatchFillData",
|
||||
"name": "fillData",
|
||||
"type": "tuple"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "batchFill",
|
||||
"outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@@ -601,6 +638,60 @@
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" },
|
||||
{ "internalType": "uint128", "name": "makerAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "takerAmount", "type": "uint128" },
|
||||
{ "internalType": "address", "name": "maker", "type": "address" },
|
||||
{ "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "internalType": "address", "name": "txOrigin", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" }
|
||||
],
|
||||
"internalType": "struct LibNativeOrder.OtcOrder[]",
|
||||
"name": "orders",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum LibSignature.SignatureType",
|
||||
"name": "signatureType",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint8", "name": "v", "type": "uint8" },
|
||||
{ "internalType": "bytes32", "name": "r", "type": "bytes32" },
|
||||
{ "internalType": "bytes32", "name": "s", "type": "bytes32" }
|
||||
],
|
||||
"internalType": "struct LibSignature.Signature[]",
|
||||
"name": "makerSignatures",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum LibSignature.SignatureType",
|
||||
"name": "signatureType",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint8", "name": "v", "type": "uint8" },
|
||||
{ "internalType": "bytes32", "name": "r", "type": "bytes32" },
|
||||
{ "internalType": "bytes32", "name": "s", "type": "bytes32" }
|
||||
],
|
||||
"internalType": "struct LibSignature.Signature[]",
|
||||
"name": "takerSignatures",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "bool[]", "name": "unwrapWeth", "type": "bool[]" }
|
||||
],
|
||||
"name": "batchFillTakerSignedOtcOrders",
|
||||
"outputs": [{ "internalType": "bool[]", "name": "successes", "type": "bool[]" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1026,8 +1117,7 @@
|
||||
"name": "makerSignature",
|
||||
"type": "tuple"
|
||||
},
|
||||
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" },
|
||||
{ "internalType": "bool", "name": "unwrapWeth", "type": "bool" }
|
||||
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }
|
||||
],
|
||||
"name": "fillOtcOrder",
|
||||
"outputs": [
|
||||
@@ -1037,6 +1127,48 @@
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" },
|
||||
{ "internalType": "uint128", "name": "makerAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "takerAmount", "type": "uint128" },
|
||||
{ "internalType": "address", "name": "maker", "type": "address" },
|
||||
{ "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "internalType": "address", "name": "txOrigin", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" }
|
||||
],
|
||||
"internalType": "struct LibNativeOrder.OtcOrder",
|
||||
"name": "order",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum LibSignature.SignatureType",
|
||||
"name": "signatureType",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint8", "name": "v", "type": "uint8" },
|
||||
{ "internalType": "bytes32", "name": "r", "type": "bytes32" },
|
||||
{ "internalType": "bytes32", "name": "s", "type": "bytes32" }
|
||||
],
|
||||
"internalType": "struct LibSignature.Signature",
|
||||
"name": "makerSignature",
|
||||
"type": "tuple"
|
||||
},
|
||||
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }
|
||||
],
|
||||
"name": "fillOtcOrderForEth",
|
||||
"outputs": [
|
||||
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1168,14 +1300,63 @@
|
||||
"internalType": "struct LibSignature.Signature",
|
||||
"name": "takerSignature",
|
||||
"type": "tuple"
|
||||
},
|
||||
{ "internalType": "bool", "name": "unwrapWeth", "type": "bool" }
|
||||
}
|
||||
],
|
||||
"name": "fillTakerSignedOtcOrder",
|
||||
"outputs": [
|
||||
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" },
|
||||
{ "internalType": "uint128", "name": "makerAmount", "type": "uint128" },
|
||||
{ "internalType": "uint128", "name": "takerAmount", "type": "uint128" },
|
||||
{ "internalType": "address", "name": "maker", "type": "address" },
|
||||
{ "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "internalType": "address", "name": "txOrigin", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" }
|
||||
],
|
||||
"internalType": "struct LibNativeOrder.OtcOrder",
|
||||
"name": "order",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum LibSignature.SignatureType",
|
||||
"name": "signatureType",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint8", "name": "v", "type": "uint8" },
|
||||
{ "internalType": "bytes32", "name": "r", "type": "bytes32" },
|
||||
{ "internalType": "bytes32", "name": "s", "type": "bytes32" }
|
||||
],
|
||||
"internalType": "struct LibSignature.Signature",
|
||||
"name": "makerSignature",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum LibSignature.SignatureType",
|
||||
"name": "signatureType",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint8", "name": "v", "type": "uint8" },
|
||||
{ "internalType": "bytes32", "name": "r", "type": "bytes32" },
|
||||
{ "internalType": "bytes32", "name": "s", "type": "bytes32" }
|
||||
],
|
||||
"internalType": "struct LibSignature.Signature",
|
||||
"name": "takerSignature",
|
||||
"type": "tuple"
|
||||
}
|
||||
],
|
||||
"name": "fillTakerSignedOtcOrderForEth",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
@@ -1604,31 +1785,150 @@
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" },
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "address[]", "name": "tokens", "type": "address[]" },
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "bytes4", "name": "selector", "type": "bytes4" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.WrappedMultiHopCall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
"internalType": "enum IMultiplexFeature.MultiplexSubcall",
|
||||
"name": "id",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.MultiHopFillData",
|
||||
"name": "fillData",
|
||||
"type": "tuple"
|
||||
"internalType": "struct IMultiplexFeature.BatchSellSubcall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "multiHopFill",
|
||||
"outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }],
|
||||
"name": "multiplexBatchSellEthForToken",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" },
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum IMultiplexFeature.MultiplexSubcall",
|
||||
"name": "id",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.BatchSellSubcall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "multiplexBatchSellTokenForEth",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" },
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum IMultiplexFeature.MultiplexSubcall",
|
||||
"name": "id",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.BatchSellSubcall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "multiplexBatchSellTokenForToken",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "address[]", "name": "tokens", "type": "address[]" },
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum IMultiplexFeature.MultiplexSubcall",
|
||||
"name": "id",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "multiplexMultiHopSellEthForToken",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "address[]", "name": "tokens", "type": "address[]" },
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum IMultiplexFeature.MultiplexSubcall",
|
||||
"name": "id",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "multiplexMultiHopSellTokenForEth",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "address[]", "name": "tokens", "type": "address[]" },
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "enum IMultiplexFeature.MultiplexSubcall",
|
||||
"name": "id",
|
||||
"type": "uint8"
|
||||
},
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]",
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "multiplexMultiHopSellTokenForToken",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
@@ -1819,20 +2119,47 @@
|
||||
"takerTokenFilledAmount": "How much maker token was filled."
|
||||
}
|
||||
},
|
||||
"_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address)": {
|
||||
"_fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": {
|
||||
"details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Internal variant.",
|
||||
"params": {
|
||||
"makerSignature": "The order signature from the maker.",
|
||||
"order": "The OTC order.",
|
||||
"recipient": "The recipient of the bought maker tokens.",
|
||||
"taker": "The address to fill the order in the context of.",
|
||||
"takerTokenFillAmount": "Maximum taker token amount to fill this order with.",
|
||||
"useSelfBalance": "Whether to use the Exchange Proxy's balance of input tokens."
|
||||
},
|
||||
"returns": {
|
||||
"makerTokenFilledAmount": "How much maker token was filled.",
|
||||
"takerTokenFilledAmount": "How much taker token was filled."
|
||||
}
|
||||
},
|
||||
"_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": {
|
||||
"details": "Fill an RFQ order. Internal variant.",
|
||||
"params": {
|
||||
"order": "The RFQ order.",
|
||||
"recipient": "The recipient of the maker tokens.",
|
||||
"signature": "The order signature.",
|
||||
"taker": "The order taker.",
|
||||
"takerTokenFillAmount": "Maximum taker token to fill this order with."
|
||||
"takerTokenFillAmount": "Maximum taker token to fill this order with.",
|
||||
"useSelfBalance": "Whether to use the ExchangeProxy's transient balance of taker tokens to fill the order."
|
||||
},
|
||||
"returns": {
|
||||
"makerTokenFilledAmount": "How much maker token was filled.",
|
||||
"takerTokenFilledAmount": "How much maker token was filled."
|
||||
}
|
||||
},
|
||||
"_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[]))": {
|
||||
"_sellHeldTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": {
|
||||
"details": "Sell a token for another token directly against uniswap v3. Private variant, uses tokens held by `address(this)`.",
|
||||
"params": {
|
||||
"encodedPath": "Uniswap-encoded path.",
|
||||
"minBuyAmount": "Minimum amount of the last token in the path to buy.",
|
||||
"recipient": "The recipient of the bought tokens. Can be zero for sender.",
|
||||
"sellAmount": "amount of the first token in the path to sell."
|
||||
},
|
||||
"returns": { "buyAmount": "Amount of the last token in the path bought." }
|
||||
},
|
||||
"_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))": {
|
||||
"details": "Internal version of `transformERC20()`. Only callable from within.",
|
||||
"params": { "args": "A `TransformERC20Args` struct." },
|
||||
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." }
|
||||
@@ -1887,14 +2214,6 @@
|
||||
},
|
||||
"returns": { "returnResults": "The ABI-encoded results of the underlying calls." }
|
||||
},
|
||||
"batchFill((address,address,uint256,(bytes4,uint256,bytes)[]),uint256)": {
|
||||
"details": "Executes a batch of fills selling `fillData.inputToken` for `fillData.outputToken` in sequence. Refer to the internal variant `_batchFill` for the allowed nested operations.",
|
||||
"params": {
|
||||
"fillData": "Encodes the input/output tokens, the sell amount, and the nested operations for this batch fill.",
|
||||
"minBuyAmount": "The minimum amount of `fillData.outputToken` to buy. Reverts if this amount is not met."
|
||||
},
|
||||
"returns": { "outputTokenAmount": "The amount of the output token bought." }
|
||||
},
|
||||
"batchFillLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": {
|
||||
"details": "Fills multiple limit orders.",
|
||||
"params": {
|
||||
@@ -1921,6 +2240,18 @@
|
||||
"takerTokenFilledAmounts": "Array of amounts filled, in taker token."
|
||||
}
|
||||
},
|
||||
"batchFillTakerSignedOtcOrders((address,address,uint128,uint128,address,address,address,uint256)[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[],bool[])": {
|
||||
"details": "Fills multiple taker-signed OTC orders.",
|
||||
"params": {
|
||||
"makerSignatures": "Array of maker signatures for each order.",
|
||||
"orders": "Array of OTC orders.",
|
||||
"takerSignatures": "Array of taker signatures for each order.",
|
||||
"unwrapWeth": "Array of booleans representing whether or not to unwrap bought WETH into ETH for each order. Should be set to false if the maker token is not WETH."
|
||||
},
|
||||
"returns": {
|
||||
"successes": "Array of booleans representing whether or not each order in `orders` was filled successfully."
|
||||
}
|
||||
},
|
||||
"batchGetLimitOrderRelevantStates((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[])": {
|
||||
"details": "Batch version of `getLimitOrderRelevantState()`, without reverting. Orders that would normally cause `getLimitOrderRelevantState()` to revert will have empty results.",
|
||||
"params": { "orders": "The limit orders.", "signatures": "The order signatures." },
|
||||
@@ -2027,13 +2358,24 @@
|
||||
},
|
||||
"returns": { "makerTokenFilledAmount": "How much maker token was filled." }
|
||||
},
|
||||
"fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,bool)": {
|
||||
"fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": {
|
||||
"details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens.",
|
||||
"params": {
|
||||
"makerSignature": "The order signature from the maker.",
|
||||
"order": "The OTC order.",
|
||||
"takerTokenFillAmount": "Maximum taker token amount to fill this order with.",
|
||||
"unwrapWeth": "Whether or not to unwrap bought WETH into ETH before transferring it to the taker. Should be set to false"
|
||||
"takerTokenFillAmount": "Maximum taker token amount to fill this order with."
|
||||
},
|
||||
"returns": {
|
||||
"makerTokenFilledAmount": "How much maker token was filled.",
|
||||
"takerTokenFilledAmount": "How much taker token was filled."
|
||||
}
|
||||
},
|
||||
"fillOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": {
|
||||
"details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Unwraps bought WETH into ETH before sending it to the taker.",
|
||||
"params": {
|
||||
"makerSignature": "The order signature from the maker.",
|
||||
"order": "The OTC order.",
|
||||
"takerTokenFillAmount": "Maximum taker token amount to fill this order with."
|
||||
},
|
||||
"returns": {
|
||||
"makerTokenFilledAmount": "How much maker token was filled.",
|
||||
@@ -2060,17 +2402,20 @@
|
||||
"takerTokenFilledAmount": "How much maker token was filled."
|
||||
}
|
||||
},
|
||||
"fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32),bool)": {
|
||||
"fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": {
|
||||
"details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker.",
|
||||
"params": {
|
||||
"makerSignature": "The order signature from the maker.",
|
||||
"order": "The OTC order.",
|
||||
"takerSignature": "The order signature from the taker.",
|
||||
"unwrapWeth": "Whether or not to unwrap bought WETH into ETH before transferring it to the taker. Should be set to false if the maker token is not WETH."
|
||||
},
|
||||
"returns": {
|
||||
"makerTokenFilledAmount": "How much maker token was filled.",
|
||||
"takerTokenFilledAmount": "How much taker token was filled."
|
||||
"takerSignature": "The order signature from the taker."
|
||||
}
|
||||
},
|
||||
"fillTakerSignedOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": {
|
||||
"details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker. Unwraps bought WETH into ETH before sending it to the taker.",
|
||||
"params": {
|
||||
"makerSignature": "The order signature from the maker.",
|
||||
"order": "The OTC order.",
|
||||
"takerSignature": "The order signature from the taker."
|
||||
}
|
||||
},
|
||||
"getLimitOrderHash((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": {
|
||||
@@ -2184,13 +2529,62 @@
|
||||
"target": "The migrator contract address."
|
||||
}
|
||||
},
|
||||
"multiHopFill((address[],uint256,(bytes4,bytes)[]),uint256)": {
|
||||
"details": "Executes a sequence of fills \"hopping\" through the path of tokens given by `fillData.tokens`. Refer to the internal variant `_multiHopFill` for the allowed nested operations.",
|
||||
"multiplexBatchSellEthForToken(address,(uint8,uint256,bytes)[],uint256)": {
|
||||
"details": "Sells attached ETH for `outputToken` using the provided calls.",
|
||||
"params": {
|
||||
"fillData": "Encodes the path of tokens, the sell amount, and the nested operations for this multi-hop fill.",
|
||||
"minBuyAmount": "The minimum amount of the output token to buy. Reverts if this amount is not met."
|
||||
"calls": "The calls to use to sell the attached ETH.",
|
||||
"minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.",
|
||||
"outputToken": "The token to buy."
|
||||
},
|
||||
"returns": { "outputTokenAmount": "The amount of the output token bought." }
|
||||
"returns": { "boughtAmount": "The amount of `outputToken` bought." }
|
||||
},
|
||||
"multiplexBatchSellTokenForEth(address,(uint8,uint256,bytes)[],uint256,uint256)": {
|
||||
"details": "Sells `sellAmount` of the given `inputToken` for ETH using the provided calls.",
|
||||
"params": {
|
||||
"calls": "The calls to use to sell the input tokens.",
|
||||
"inputToken": "The token to sell.",
|
||||
"minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.",
|
||||
"sellAmount": "The amount of `inputToken` to sell."
|
||||
},
|
||||
"returns": { "boughtAmount": "The amount of ETH bought." }
|
||||
},
|
||||
"multiplexBatchSellTokenForToken(address,address,(uint8,uint256,bytes)[],uint256,uint256)": {
|
||||
"details": "Sells `sellAmount` of the given `inputToken` for `outputToken` using the provided calls.",
|
||||
"params": {
|
||||
"calls": "The calls to use to sell the input tokens.",
|
||||
"inputToken": "The token to sell.",
|
||||
"minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.",
|
||||
"outputToken": "The token to buy.",
|
||||
"sellAmount": "The amount of `inputToken` to sell."
|
||||
},
|
||||
"returns": { "boughtAmount": "The amount of `outputToken` bought." }
|
||||
},
|
||||
"multiplexMultiHopSellEthForToken(address[],(uint8,bytes)[],uint256)": {
|
||||
"details": "Sells attached ETH via the given sequence of tokens and calls. `tokens[0]` must be WETH. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`",
|
||||
"params": {
|
||||
"calls": "The sequence of calls to use for the sell.",
|
||||
"minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.",
|
||||
"tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`."
|
||||
},
|
||||
"returns": { "boughtAmount": "The amount of output tokens bought." }
|
||||
},
|
||||
"multiplexMultiHopSellTokenForEth(address[],(uint8,bytes)[],uint256,uint256)": {
|
||||
"details": "Sells `sellAmount` of the input token (`tokens[0]`) for ETH via the given sequence of tokens and calls. The last token in `tokens` must be WETH.",
|
||||
"params": {
|
||||
"calls": "The sequence of calls to use for the sell.",
|
||||
"minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.",
|
||||
"tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`."
|
||||
},
|
||||
"returns": { "boughtAmount": "The amount of ETH bought." }
|
||||
},
|
||||
"multiplexMultiHopSellTokenForToken(address[],(uint8,bytes)[],uint256,uint256)": {
|
||||
"details": "Sells `sellAmount` of the input token (`tokens[0]`) via the given sequence of tokens and calls. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`",
|
||||
"params": {
|
||||
"calls": "The sequence of calls to use for the sell.",
|
||||
"minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.",
|
||||
"tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`."
|
||||
},
|
||||
"returns": { "boughtAmount": "The amount of output tokens bought." }
|
||||
},
|
||||
"owner()": {
|
||||
"details": "The owner of this contract.",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contract-artifacts",
|
||||
"version": "3.15.0",
|
||||
"version": "3.16.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/packages/contract-artifacts",
|
||||
"devDependencies": {
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"chai": "^4.0.1",
|
||||
"lodash": "^4.17.11",
|
||||
|
@@ -1,4 +1,32 @@
|
||||
[
|
||||
{
|
||||
"version": "13.18.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update IZeroEx and ITransformERC20 wrappers",
|
||||
"pr": 282
|
||||
}
|
||||
],
|
||||
"timestamp": 1632957537
|
||||
},
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "13.17.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "13.17.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "13.17.5",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v13.18.0 - _September 29, 2021_
|
||||
|
||||
* Update IZeroEx and ITransformERC20 wrappers (#282)
|
||||
|
||||
## v13.17.7 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v13.17.6 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v13.17.5 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contract-wrappers",
|
||||
"version": "13.17.5",
|
||||
"version": "13.18.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -55,14 +55,14 @@
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"@0x/assert": "^3.0.29",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/json-schemas": "^6.3.0",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethers": "~4.0.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -269,12 +269,12 @@ export class ITransformERC20Contract extends BaseContract {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'callDataHash',
|
||||
type: 'bytes32',
|
||||
name: 'useSelfBalance',
|
||||
type: 'bool',
|
||||
},
|
||||
{
|
||||
name: 'callDataSignature',
|
||||
type: 'bytes',
|
||||
name: 'recipient',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -497,13 +497,13 @@ export class ITransformERC20Contract extends BaseContract {
|
||||
inputTokenAmount: BigNumber;
|
||||
minOutputTokenAmount: BigNumber;
|
||||
transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>;
|
||||
callDataHash: string;
|
||||
callDataSignature: string;
|
||||
useSelfBalance: boolean;
|
||||
recipient: string;
|
||||
}): ContractTxFunctionObj<BigNumber> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
|
||||
const functionSignature =
|
||||
'_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bytes32,bytes))';
|
||||
'_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -126,7 +126,6 @@ export {
|
||||
IZeroExContract,
|
||||
IZeroExEventArgs,
|
||||
IZeroExEvents,
|
||||
IZeroExExpiredRfqOrderEventArgs,
|
||||
IZeroExLiquidityProviderSwapEventArgs,
|
||||
IZeroExMetaTransactionExecutedEventArgs,
|
||||
IZeroExMigratedEventArgs,
|
||||
|
@@ -1,4 +1,49 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1633374058,
|
||||
"version": "8.1.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1632957537,
|
||||
"version": "8.1.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631710679,
|
||||
"version": "8.1.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1631120757,
|
||||
"version": "8.1.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "8.1.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629414734,
|
||||
"version": "8.1.3",
|
||||
|
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v8.1.8 - _October 4, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v8.1.7 - _September 29, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v8.1.6 - _September 15, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v8.1.5 - _September 8, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v8.1.4 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v8.1.3 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/migrations",
|
||||
"version": "8.1.3",
|
||||
"version": "8.1.8",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -48,10 +48,10 @@
|
||||
"registry": "git@github.com:0xProject/gitpkg-registry.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@types/yargs": "^11.0.0",
|
||||
"chai": "^4.0.1",
|
||||
"dirty-chai": "^2.0.1",
|
||||
@@ -67,29 +67,29 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.4.0",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/base-contract": "^6.4.2",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/contracts-asset-proxy": "^3.7.19",
|
||||
"@0x/contracts-coordinator": "^3.1.38",
|
||||
"@0x/contracts-dev-utils": "^1.3.36",
|
||||
"@0x/contracts-erc1155": "^2.1.37",
|
||||
"@0x/contracts-erc20": "^3.3.17",
|
||||
"@0x/contracts-erc20": "^3.3.20",
|
||||
"@0x/contracts-erc721": "^3.1.37",
|
||||
"@0x/contracts-exchange": "^3.2.38",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.38",
|
||||
"@0x/contracts-extensions": "^6.2.32",
|
||||
"@0x/contracts-multisig": "^4.1.38",
|
||||
"@0x/contracts-staking": "^2.0.45",
|
||||
"@0x/contracts-utils": "^4.7.17",
|
||||
"@0x/contracts-zero-ex": "^0.28.2",
|
||||
"@0x/sol-compiler": "^4.7.3",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"@0x/contracts-utils": "^4.8.1",
|
||||
"@0x/contracts-zero-ex": "^0.29.1",
|
||||
"@0x/sol-compiler": "^4.7.5",
|
||||
"@0x/subproviders": "^6.6.0",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"@ledgerhq/hw-app-eth": "^4.3.0",
|
||||
"@types/web3-provider-engine": "^14.0.0",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"ethereumjs-util": "^7.1.0",
|
||||
"ethers": "~4.0.4",
|
||||
"lodash": "^4.17.11"
|
||||
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1633374058,
|
||||
"version": "1.9.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1632957537,
|
||||
"version": "1.9.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.9.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add 'TreasuryVote' class"
|
||||
}
|
||||
],
|
||||
"timestamp": 1631710679
|
||||
},
|
||||
{
|
||||
"timestamp": 1630459879,
|
||||
"version": "1.8.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1629353596,
|
||||
"version": "1.8.3",
|
||||
|
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.9.2 - _October 4, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.9.1 - _September 29, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.9.0 - _September 15, 2021_
|
||||
|
||||
* Add 'TreasuryVote' class
|
||||
|
||||
## v1.8.4 - _September 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.8.3 - _August 19, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/protocol-utils",
|
||||
"version": "1.8.3",
|
||||
"version": "1.9.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,17 +41,17 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/packages/protocol-utils",
|
||||
"devDependencies": {
|
||||
"@0x/dev-utils": "^4.2.7",
|
||||
"@0x/dev-utils": "^4.2.9",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/types": "^3.3.4",
|
||||
"@0x/typescript-typings": "^5.2.1",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "12.12.54",
|
||||
"@types/web3-provider-engine": "^14.0.0",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"ethereum-types": "^3.6.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
@@ -62,13 +62,13 @@
|
||||
"web3-provider-engine": "14.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.27",
|
||||
"@0x/contract-addresses": "^6.6.1",
|
||||
"@0x/contract-wrappers": "^13.17.5",
|
||||
"@0x/json-schemas": "^6.1.3",
|
||||
"@0x/subproviders": "^6.5.3",
|
||||
"@0x/utils": "^6.4.3",
|
||||
"@0x/web3-wrapper": "^7.5.3",
|
||||
"@0x/assert": "^3.0.29",
|
||||
"@0x/contract-addresses": "^6.7.0",
|
||||
"@0x/contract-wrappers": "^13.18.0",
|
||||
"@0x/json-schemas": "^6.3.0",
|
||||
"@0x/subproviders": "^6.6.0",
|
||||
"@0x/utils": "^6.4.4",
|
||||
"@0x/web3-wrapper": "^7.6.0",
|
||||
"chai": "^4.0.1",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"ethers": "~4.0.4",
|
||||
|
@@ -9,3 +9,4 @@ export * from './signature_utils';
|
||||
export * from './transformer_utils';
|
||||
export * from './constants';
|
||||
export * from './vip_utils';
|
||||
export * from './treasury_votes';
|
||||
|
@@ -131,7 +131,7 @@ export enum BridgeProtocol {
|
||||
KyberDmm,
|
||||
CurveV2,
|
||||
Lido,
|
||||
Clipper,
|
||||
Clipper, // Not used: Clipper is now using PLP interface
|
||||
}
|
||||
// tslint:enable: enum-naming
|
||||
|
||||
|
85
packages/protocol-utils/src/treasury_votes.ts
Normal file
85
packages/protocol-utils/src/treasury_votes.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { ZERO } from './constants';
|
||||
import { EIP712_DOMAIN_PARAMETERS, getTypeHash } from './eip712_utils';
|
||||
import { eip712SignHashWithKey, Signature } from './signature_utils';
|
||||
|
||||
const VOTE_DEFAULT_VALUES = {
|
||||
proposalId: ZERO,
|
||||
support: false,
|
||||
operatedPoolIds: [] as string[],
|
||||
chainId: 1,
|
||||
version: '1.0.0',
|
||||
verifyingContract: NULL_ADDRESS,
|
||||
};
|
||||
|
||||
export type TreasuryVoteFields = typeof VOTE_DEFAULT_VALUES;
|
||||
|
||||
export class TreasuryVote {
|
||||
public static readonly CONTRACT_NAME = 'Zrx Treasury';
|
||||
|
||||
public static readonly MESSAGE_STRUCT_NAME = 'TreasuryVote';
|
||||
public static readonly MESSAGE_STRUCT_ABI = [
|
||||
{ type: 'uint256', name: 'proposalId' },
|
||||
{ type: 'bool', name: 'support' },
|
||||
{ type: 'bytes32[]', name: 'operatedPoolIds' },
|
||||
];
|
||||
public static readonly MESSAGE_TYPE_HASH = getTypeHash(
|
||||
TreasuryVote.MESSAGE_STRUCT_NAME,
|
||||
TreasuryVote.MESSAGE_STRUCT_ABI,
|
||||
);
|
||||
|
||||
public static readonly DOMAIN_STRUCT_NAME = 'EIP712Domain';
|
||||
public static readonly DOMAIN_TYPE_HASH = getTypeHash(TreasuryVote.DOMAIN_STRUCT_NAME, EIP712_DOMAIN_PARAMETERS);
|
||||
|
||||
public proposalId: BigNumber;
|
||||
public support: boolean;
|
||||
public operatedPoolIds: string[];
|
||||
public chainId: number;
|
||||
public version: string;
|
||||
public verifyingContract: string;
|
||||
|
||||
constructor(fields: Partial<TreasuryVoteFields> = {}) {
|
||||
const _fields = { ...VOTE_DEFAULT_VALUES, ...fields };
|
||||
this.proposalId = _fields.proposalId;
|
||||
this.support = _fields.support;
|
||||
this.operatedPoolIds = _fields.operatedPoolIds;
|
||||
this.chainId = _fields.chainId;
|
||||
this.version = _fields.version;
|
||||
this.verifyingContract = _fields.verifyingContract;
|
||||
}
|
||||
|
||||
public getDomainHash(): string {
|
||||
return hexUtils.hash(
|
||||
hexUtils.concat(
|
||||
hexUtils.leftPad(TreasuryVote.DOMAIN_TYPE_HASH),
|
||||
hexUtils.hash(hexUtils.toHex(Buffer.from(TreasuryVote.CONTRACT_NAME))),
|
||||
hexUtils.leftPad(this.chainId),
|
||||
hexUtils.hash(hexUtils.toHex(Buffer.from(this.version))),
|
||||
hexUtils.leftPad(this.verifyingContract),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getStructHash(): string {
|
||||
return hexUtils.hash(
|
||||
hexUtils.concat(
|
||||
hexUtils.leftPad(TreasuryVote.MESSAGE_TYPE_HASH),
|
||||
hexUtils.leftPad(this.proposalId),
|
||||
hexUtils.leftPad(this.support ? 1 : 0),
|
||||
hexUtils.hash(
|
||||
ethUtil.toBuffer(hexUtils.concat(...this.operatedPoolIds.map(id => hexUtils.leftPad(id)))),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getEIP712Hash(): string {
|
||||
return hexUtils.hash(hexUtils.toHex(hexUtils.concat('0x1901', this.getDomainHash(), this.getStructHash())));
|
||||
}
|
||||
|
||||
public getSignatureWithKey(privateKey: string): Signature {
|
||||
return eip712SignHashWithKey(this.getEIP712Hash(), privateKey);
|
||||
}
|
||||
}
|
310
yarn.lock
310
yarn.lock
@@ -643,19 +643,20 @@
|
||||
npmlog "^4.1.2"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@0x/abi-gen@^5.6.0":
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@0x/abi-gen/-/abi-gen-5.6.0.tgz#2b022efe77a35f5589624633d880d794d0a16bde"
|
||||
"@0x/abi-gen@^5.6.2":
|
||||
version "5.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@0x/abi-gen/-/abi-gen-5.6.2.tgz#a31b26b93b061ceb8513424d622119c78b3ed0e9"
|
||||
integrity sha512-G+B9/VEfsOc8IOgUgkIdFiC+0RNg1DTR921WOxOxcvLsls9m9lBudl7hFrU03N1QdbFFP08e+HDj1kS2Q+SzEQ==
|
||||
dependencies:
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/types" "^3.3.4"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@types/node" "12.12.54"
|
||||
"@types/toposort" "^2.0.1"
|
||||
chalk "^2.3.0"
|
||||
change-case "^3.0.2"
|
||||
cli-format "^3.0.9"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereum-types "^3.6.0"
|
||||
glob "^7.1.2"
|
||||
handlebars "^4.1.2"
|
||||
lodash "^4.17.11"
|
||||
@@ -676,6 +677,18 @@
|
||||
lodash "^4.17.11"
|
||||
valid-url "^1.0.9"
|
||||
|
||||
"@0x/assert@^3.0.29":
|
||||
version "3.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@0x/assert/-/assert-3.0.29.tgz#604e415b943140a1577c9389b04766909a60b589"
|
||||
integrity sha512-EiF8TwCtM17KFcLy2FYVzu3+7K51VyUNs9ZQ/Wf8tWDeTWrIh1ixKGsNtRnL9sR5SPqOLwKR3lbGn+zPlxw+Yw==
|
||||
dependencies:
|
||||
"@0x/json-schemas" "^6.3.0"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@types/node" "12.12.54"
|
||||
lodash "^4.17.11"
|
||||
valid-url "^1.0.9"
|
||||
|
||||
"@0x/assert@^3.0.6":
|
||||
version "3.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@0x/assert/-/assert-3.0.21.tgz#b385868d1833625912fd9173a2477be5a4090aed"
|
||||
@@ -704,6 +717,24 @@
|
||||
js-sha3 "^0.7.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
"@0x/base-contract@^6.4.2":
|
||||
version "6.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@0x/base-contract/-/base-contract-6.4.2.tgz#d87cb5416613d29d2ec71c60d4a7c6cdd5c48694"
|
||||
integrity sha512-lcmsXGJ2ImiO1tJoWefYiQ8/WRSdQ4BPA8XulYqVQ4su6PYjLa1XvU91zM779QrIPeRo8fL7FUvGE7CkyG/gwA==
|
||||
dependencies:
|
||||
"@0x/assert" "^3.0.29"
|
||||
"@0x/json-schemas" "^6.3.0"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@0x/web3-wrapper" "^7.6.0"
|
||||
"@types/node" "12.12.54"
|
||||
ethereumjs-account "^3.0.0"
|
||||
ethereumjs-blockstream "^7.0.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
ethereumjs-vm "^4.2.0"
|
||||
ethers "~4.0.4"
|
||||
js-sha3 "^0.7.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
"@0x/contracts-asset-proxy@^3.7.19":
|
||||
version "3.7.19"
|
||||
resolved "https://registry.yarnpkg.com/@0x/contracts-asset-proxy/-/contracts-asset-proxy-3.7.19.tgz#ee621a233f4d77b439c74c5b8d70db2e1ed001c4"
|
||||
@@ -804,17 +835,18 @@
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
ethereum-types "^3.5.0"
|
||||
|
||||
"@0x/contracts-gen@^2.0.38":
|
||||
version "2.0.38"
|
||||
resolved "https://registry.yarnpkg.com/@0x/contracts-gen/-/contracts-gen-2.0.38.tgz#6f2977e2bcb299b5e8a32f45d7eca73d19e34c50"
|
||||
"@0x/contracts-gen@^2.0.40":
|
||||
version "2.0.40"
|
||||
resolved "https://registry.yarnpkg.com/@0x/contracts-gen/-/contracts-gen-2.0.40.tgz#526c25991125b5a4deb745e470b3c64cd8673095"
|
||||
integrity sha512-Luj6R4DtPI7KHr3tUSdarudNiySd6GY1mvfhu8566K76oq4aK1no1hf0pyvy9tQLJDViNePP8Ad5KcEmC89sAg==
|
||||
dependencies:
|
||||
"@0x/sol-compiler" "^4.7.3"
|
||||
"@0x/sol-resolver" "^3.1.8"
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/sol-compiler" "^4.7.5"
|
||||
"@0x/sol-resolver" "^3.1.9"
|
||||
"@0x/types" "^3.3.4"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@types/node" "12.12.54"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereum-types "^3.6.0"
|
||||
lodash "^4.17.11"
|
||||
mkdirp "^0.5.1"
|
||||
prettier "^1.16.3"
|
||||
@@ -839,36 +871,23 @@
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
|
||||
"@0x/contracts-zero-ex@^0.27.0":
|
||||
version "0.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@0x/contracts-zero-ex/-/contracts-zero-ex-0.27.1.tgz#968fe9d8134972cb464f7c4a33c4e4089ba9218e"
|
||||
"@0x/dev-utils@^4.2.9":
|
||||
version "4.2.9"
|
||||
resolved "https://registry.yarnpkg.com/@0x/dev-utils/-/dev-utils-4.2.9.tgz#b048b139b0055ef3702682c42ccc2a3788a49f5d"
|
||||
integrity sha512-juIjVvky0umt7Tmzhz2PF7e7pQEe1hbrV2XyB5tocRQVAsTD+TuwTG9VVKULQUptX+B/mF1mjb3WwEQV6y/yTQ==
|
||||
dependencies:
|
||||
"@0x/base-contract" "^6.4.0"
|
||||
"@0x/protocol-utils" "^1.8.1"
|
||||
"@0x/subproviders" "^6.5.3"
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/web3-wrapper" "^7.5.3"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
|
||||
"@0x/dev-utils@^4.2.7":
|
||||
version "4.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@0x/dev-utils/-/dev-utils-4.2.7.tgz#9c85a134cace5a423a75221241fd687df81f3bbc"
|
||||
dependencies:
|
||||
"@0x/subproviders" "^6.5.3"
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/web3-wrapper" "^7.5.3"
|
||||
"@0x/subproviders" "^6.6.0"
|
||||
"@0x/types" "^3.3.4"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@0x/web3-wrapper" "^7.6.0"
|
||||
"@types/node" "12.12.54"
|
||||
"@types/web3-provider-engine" "^14.0.0"
|
||||
chai "^4.0.1"
|
||||
chai-as-promised "^7.1.0"
|
||||
chai-bignumber "^3.0.0"
|
||||
dirty-chai "^2.0.1"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereum-types "^3.6.0"
|
||||
lodash "^4.17.11"
|
||||
web3-provider-engine "14.0.6"
|
||||
|
||||
@@ -890,6 +909,16 @@
|
||||
ajv "^6.12.5"
|
||||
lodash.values "^4.3.0"
|
||||
|
||||
"@0x/json-schemas@^6.3.0":
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@0x/json-schemas/-/json-schemas-6.3.0.tgz#b7addf8167af492f6667561caa9a62b3ec567696"
|
||||
integrity sha512-cygnTxvJhLYcDeI05Olp4CN0BKQRs2rC3L0gRCU+mV/IMDNYlkKqNluHmzoHLBleN55uLZZZybSLOsbE5HfIlQ==
|
||||
dependencies:
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@types/node" "12.12.54"
|
||||
ajv "^6.12.5"
|
||||
lodash.values "^4.3.0"
|
||||
|
||||
"@0x/mesh-rpc-client@^9.4.2":
|
||||
version "9.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@0x/mesh-rpc-client/-/mesh-rpc-client-9.4.2.tgz#6f9690fb1cb37fb0c2fd3907241af0e543c78451"
|
||||
@@ -930,6 +959,13 @@
|
||||
typedoc "~0.16.11"
|
||||
yargs "^10.0.3"
|
||||
|
||||
"@0x/neon-router@^0.1.3":
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@0x/neon-router/-/neon-router-0.1.3.tgz#70da4c17ca4b59dfe8b5e539673e364a70e62ebd"
|
||||
integrity sha512-EfdrG829NalYjAK5/nMTD6YyJQgUzgssL2Hvyphu1ugWxWlZ3QMM9qpZsKt82hUiyZT/64I4JJ3hkerMhTaHeg==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
||||
|
||||
"@0x/order-utils@^10.2.4", "@0x/order-utils@^10.4.28":
|
||||
version "10.4.28"
|
||||
resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-10.4.28.tgz#c7b2f7d87a7f9834f9aa6186fbac68f32a05a81d"
|
||||
@@ -944,9 +980,10 @@
|
||||
ethers "~4.0.4"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@0x/quote-server@^6.0.2":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@0x/quote-server/-/quote-server-6.0.2.tgz#cb99e00c737e0f97a2a32bc7e7be6db65243c3af"
|
||||
"@0x/quote-server@^6.0.6":
|
||||
version "6.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@0x/quote-server/-/quote-server-6.0.6.tgz#0f0bf50647efc4bff039a491689974af7e8c5776"
|
||||
integrity sha512-ubugDwCFDhOv8R8LWO4Z9BmWfm/KjbB92bg1nEHw2HzosOk1rLkQWnPCJGqbMzxHlt3EtLxXPrrZE2IxWBKgwQ==
|
||||
dependencies:
|
||||
"@0x/json-schemas" "^6.0.1"
|
||||
"@0x/order-utils" "^10.2.4"
|
||||
@@ -957,23 +994,24 @@
|
||||
express-async-handler "^1.1.4"
|
||||
http-status-codes "^1.4.0"
|
||||
|
||||
"@0x/sol-compiler@^4.7.3":
|
||||
version "4.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-compiler/-/sol-compiler-4.7.3.tgz#d994661bc9c06a0a63b0e2f77ee6511d3cef488e"
|
||||
"@0x/sol-compiler@^4.7.5":
|
||||
version "4.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-compiler/-/sol-compiler-4.7.5.tgz#f744f836786f44747cfd23eb167067ce6f348136"
|
||||
integrity sha512-vVsMNFLsR7ORuriZXCWloEhDZh3loaTkiFgFI3zTne7wOCwyMntZkgA7uij/iyOGrZW0XEbxAA+QjAYenroRfQ==
|
||||
dependencies:
|
||||
"@0x/assert" "^3.0.27"
|
||||
"@0x/json-schemas" "^6.1.3"
|
||||
"@0x/sol-resolver" "^3.1.8"
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/web3-wrapper" "^7.5.3"
|
||||
"@0x/assert" "^3.0.29"
|
||||
"@0x/json-schemas" "^6.3.0"
|
||||
"@0x/sol-resolver" "^3.1.9"
|
||||
"@0x/types" "^3.3.4"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@0x/web3-wrapper" "^7.6.0"
|
||||
"@types/node" "12.12.54"
|
||||
"@types/yargs" "^11.0.0"
|
||||
chalk "^2.3.0"
|
||||
chokidar "^3.0.2"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
ethereum-types "^3.6.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
lodash "^4.17.11"
|
||||
mkdirp "^0.5.1"
|
||||
pluralize "^7.0.0"
|
||||
@@ -985,74 +1023,79 @@
|
||||
web3-eth-abi "^1.0.0-beta.24"
|
||||
yargs "^10.0.3"
|
||||
|
||||
"@0x/sol-coverage@^4.0.37":
|
||||
version "4.0.37"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-coverage/-/sol-coverage-4.0.37.tgz#951363f1497cc65edf9bc76f37ac7824667e2c2b"
|
||||
"@0x/sol-coverage@^4.0.39":
|
||||
version "4.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-coverage/-/sol-coverage-4.0.39.tgz#27db909a3f35c625bbf271fa7ecd693eb880ed53"
|
||||
integrity sha512-mARTgkNX4xkY8UVeYO1oQ0+iY9OJyeRHZbuiWizdeCRuoZth7qk8F1xbywZTCPyo6Pa4zmusi7poKRfHIFTFHA==
|
||||
dependencies:
|
||||
"@0x/sol-tracing-utils" "^7.2.3"
|
||||
"@0x/subproviders" "^6.5.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/sol-tracing-utils" "^7.2.5"
|
||||
"@0x/subproviders" "^6.6.0"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@types/minimatch" "^3.0.3"
|
||||
"@types/node" "12.12.54"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereum-types "^3.6.0"
|
||||
lodash "^4.17.11"
|
||||
minimatch "^3.0.4"
|
||||
web3-provider-engine "14.0.6"
|
||||
|
||||
"@0x/sol-profiler@^4.1.27":
|
||||
version "4.1.27"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-profiler/-/sol-profiler-4.1.27.tgz#2bd14882dd204a7465b494149877daa16d86208d"
|
||||
"@0x/sol-profiler@^4.1.29":
|
||||
version "4.1.29"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-profiler/-/sol-profiler-4.1.29.tgz#e77e0ae50541e8acaf7cecb5378a60efd4282f11"
|
||||
integrity sha512-4CbrNan9xF3auv0ZwjsoajgpqLO23eqcq1u9seSVriNs5IGxEOq4U5xxofvFIMaS0NQXnHJobuUT2qRayBbgkw==
|
||||
dependencies:
|
||||
"@0x/sol-tracing-utils" "^7.2.3"
|
||||
"@0x/subproviders" "^6.5.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/sol-tracing-utils" "^7.2.5"
|
||||
"@0x/subproviders" "^6.6.0"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@types/node" "12.12.54"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
ethereum-types "^3.6.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
lodash "^4.17.11"
|
||||
web3-provider-engine "14.0.6"
|
||||
|
||||
"@0x/sol-resolver@^3.1.8":
|
||||
version "3.1.8"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-resolver/-/sol-resolver-3.1.8.tgz#eaaaf17052e88213e55daf2c6e39a585cc16fa0a"
|
||||
"@0x/sol-resolver@^3.1.9":
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-resolver/-/sol-resolver-3.1.9.tgz#525c545c4ff4d0ff2ff99e433b2405778abe0693"
|
||||
integrity sha512-N+GxAqtHzEgVsnj9k4yeE7xRqE2ymR+yo98j0s2VC8icjecVqm6LtqQpEpdPULEg20vA0aPdU/XY2q0xiCDpLg==
|
||||
dependencies:
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/types" "^3.3.4"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@types/node" "12.12.54"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@0x/sol-trace@^3.0.37":
|
||||
version "3.0.37"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-trace/-/sol-trace-3.0.37.tgz#915a1c7c4869f9a95994fdb24878997d5bc39450"
|
||||
"@0x/sol-trace@^3.0.39":
|
||||
version "3.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-trace/-/sol-trace-3.0.39.tgz#caca4fbf049eda25185c09ab00c23cf37d44d9a2"
|
||||
integrity sha512-Dg+jPjCnSmWL4t/tq/kQY8NOnAWy/g4HjFQYyL6uz8ioJ4gvCCV+2UADATb2OA7bqrvtbADJrw7icJ+/laqXuA==
|
||||
dependencies:
|
||||
"@0x/sol-tracing-utils" "^7.2.3"
|
||||
"@0x/subproviders" "^6.5.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/sol-tracing-utils" "^7.2.5"
|
||||
"@0x/subproviders" "^6.6.0"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@types/node" "12.12.54"
|
||||
chalk "^2.3.0"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
ethereum-types "^3.6.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
lodash "^4.17.11"
|
||||
loglevel "^1.6.1"
|
||||
web3-provider-engine "14.0.6"
|
||||
|
||||
"@0x/sol-tracing-utils@^7.2.3":
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-tracing-utils/-/sol-tracing-utils-7.2.3.tgz#2a24969943315af4f86ceab12ad8bc34433069e5"
|
||||
"@0x/sol-tracing-utils@^7.2.5":
|
||||
version "7.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@0x/sol-tracing-utils/-/sol-tracing-utils-7.2.5.tgz#19ced9ecf6811dab4133ea9acf4dfdd0987b14fd"
|
||||
integrity sha512-ptffYU/KigOipFGwxWHqToQ/pbkbCyODBcxVTKeEW4MFlHeRMDRHypDM13VFAyAxqQwzvOfk22xeuLVUsKwPVQ==
|
||||
dependencies:
|
||||
"@0x/dev-utils" "^4.2.7"
|
||||
"@0x/sol-compiler" "^4.7.3"
|
||||
"@0x/sol-resolver" "^3.1.8"
|
||||
"@0x/subproviders" "^6.5.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/web3-wrapper" "^7.5.3"
|
||||
"@0x/dev-utils" "^4.2.9"
|
||||
"@0x/sol-compiler" "^4.7.5"
|
||||
"@0x/sol-resolver" "^3.1.9"
|
||||
"@0x/subproviders" "^6.6.0"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@0x/web3-wrapper" "^7.6.0"
|
||||
"@types/node" "12.12.54"
|
||||
"@types/solidity-parser-antlr" "^0.2.3"
|
||||
chalk "^2.3.0"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
ethereum-types "^3.6.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
ethers "~4.0.4"
|
||||
glob "^7.1.2"
|
||||
istanbul "^0.4.5"
|
||||
@@ -1064,17 +1107,18 @@
|
||||
solc "^0.5.5"
|
||||
solidity-parser-antlr "^0.4.2"
|
||||
|
||||
"@0x/subproviders@^6.5.3":
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.5.3.tgz#aec86903527c8f972beec1bc2fbda5fdba361235"
|
||||
"@0x/subproviders@^6.6.0":
|
||||
version "6.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.6.0.tgz#1743d44ae5e2be9ec48caddbf0f1a580f1672d32"
|
||||
integrity sha512-fQ4efPH/io+TAYEsZuYj9YpoAy0fGWx8QZaWeNstxFT2Miph2aq4Bh+GGrQcXSjNx+prgdBDAGePJvtGP8Qs3Q==
|
||||
dependencies:
|
||||
"@0x/assert" "^3.0.27"
|
||||
"@0x/types" "^3.3.3"
|
||||
"@0x/typescript-typings" "^5.2.0"
|
||||
"@0x/utils" "^6.4.3"
|
||||
"@0x/web3-wrapper" "^7.5.3"
|
||||
"@ethereumjs/common" "^2.2.0"
|
||||
"@ethereumjs/tx" "^3.1.3"
|
||||
"@0x/assert" "^3.0.29"
|
||||
"@0x/types" "^3.3.4"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@0x/web3-wrapper" "^7.6.0"
|
||||
"@ethereumjs/common" "^2.4.0"
|
||||
"@ethereumjs/tx" "^3.3.0"
|
||||
"@ledgerhq/hw-app-eth" "^4.3.0"
|
||||
"@ledgerhq/hw-transport-u2f" "4.24.0"
|
||||
"@types/hdkey" "^0.7.0"
|
||||
@@ -1082,8 +1126,8 @@
|
||||
"@types/web3-provider-engine" "^14.0.0"
|
||||
bip39 "^2.5.0"
|
||||
bn.js "^4.11.8"
|
||||
ethereum-types "^3.5.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
ethereum-types "^3.6.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
ganache-core "^2.13.2"
|
||||
hdkey "^0.7.1"
|
||||
json-rpc-error "2.0.0"
|
||||
@@ -1284,6 +1328,21 @@
|
||||
ethers "~4.0.4"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@0x/web3-wrapper@^7.6.0":
|
||||
version "7.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@0x/web3-wrapper/-/web3-wrapper-7.6.0.tgz#34ae5e32affc02ed425c7bb3402a26fd7880c999"
|
||||
integrity sha512-yxvTT/w5PFfnbKZ9Xvt412fyhVfiNQ0ugFbJYr+X+Xye+Q9vZzzbfc2a3bJSO7w/HkZx7vND071F/jtqU1JsEg==
|
||||
dependencies:
|
||||
"@0x/assert" "^3.0.29"
|
||||
"@0x/json-schemas" "^6.3.0"
|
||||
"@0x/typescript-typings" "^5.2.1"
|
||||
"@0x/utils" "^6.4.4"
|
||||
"@types/node" "12.12.54"
|
||||
ethereum-types "^3.6.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
ethers "~4.0.4"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@0xproject/npm-cli-login@^0.0.11":
|
||||
version "0.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@0xproject/npm-cli-login/-/npm-cli-login-0.0.11.tgz#3f1ec06112ce62aad300ff0575358f68aeecde2e"
|
||||
@@ -1346,19 +1405,21 @@
|
||||
web3 "1.2.1"
|
||||
web3-typescript-typings "^0.10.2"
|
||||
|
||||
"@ethereumjs/common@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.2.0.tgz#850a3e3e594ee707ad8d44a11e8152fb62450535"
|
||||
"@ethereumjs/common@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.4.0.tgz#2d67f6e6ba22246c5c89104e6b9a119fb3039766"
|
||||
integrity sha512-UdkhFWzWcJCZVsj1O/H8/oqj/0RVYjLc1OhPjBrQdALAkQHpCp8xXI4WLnuGTADqTdJZww0NtgwG+TRPkXt27w==
|
||||
dependencies:
|
||||
crc-32 "^1.2.0"
|
||||
ethereumjs-util "^7.0.9"
|
||||
ethereumjs-util "^7.1.0"
|
||||
|
||||
"@ethereumjs/tx@^3.1.3":
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.1.4.tgz#04cf9e9406da5f04a1a26c458744641f4b4b8dd0"
|
||||
"@ethereumjs/tx@^3.3.0":
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.0.tgz#14ed1b7fa0f28e1cd61e3ecbdab824205f6a4378"
|
||||
integrity sha512-yTwEj2lVzSMgE6Hjw9Oa1DZks/nKTWM8Wn4ykDNapBPua2f4nXO3qKnni86O6lgDj5fVNRqbDsD0yy7/XNGDEA==
|
||||
dependencies:
|
||||
"@ethereumjs/common" "^2.2.0"
|
||||
ethereumjs-util "^7.0.10"
|
||||
"@ethereumjs/common" "^2.4.0"
|
||||
ethereumjs-util "^7.1.0"
|
||||
|
||||
"@ethersproject/abi@5.0.0-beta.153":
|
||||
version "5.0.0-beta.153"
|
||||
@@ -2419,6 +2480,21 @@
|
||||
semver "^7.3.4"
|
||||
tar "^6.1.0"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950"
|
||||
integrity sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
https-proxy-agent "^5.0.0"
|
||||
make-dir "^3.1.0"
|
||||
node-fetch "^2.6.1"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^4.1.2"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.4"
|
||||
tar "^6.1.0"
|
||||
|
||||
"@mrmlnc/readdir-enhanced@^2.2.1":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
||||
@@ -5996,7 +6072,7 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum
|
||||
rlp "^2.0.0"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.9:
|
||||
ethereumjs-util@^7.0.10:
|
||||
version "7.0.10"
|
||||
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f"
|
||||
dependencies:
|
||||
|
Reference in New Issue
Block a user