Working towards maker signature validation
This commit is contained in:
parent
1f2e94b585
commit
36b76550e0
@ -54,6 +54,7 @@
|
|||||||
"@0x/dev-utils": "^2.3.0",
|
"@0x/dev-utils": "^2.3.0",
|
||||||
"@0x/sol-compiler": "^3.1.12",
|
"@0x/sol-compiler": "^3.1.12",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
|
"@0x/utils": "^4.3.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
|
@ -24,6 +24,7 @@ import "../immutable/MixinConstants.sol";
|
|||||||
import "../interfaces/IStakingEvents.sol";
|
import "../interfaces/IStakingEvents.sol";
|
||||||
import "./MixinRewardVault.sol";
|
import "./MixinRewardVault.sol";
|
||||||
import "./MixinSignatureValidator.sol";
|
import "./MixinSignatureValidator.sol";
|
||||||
|
import "../libs/LibEIP712Hash.sol";
|
||||||
|
|
||||||
contract MixinPools is
|
contract MixinPools is
|
||||||
SafeMath,
|
SafeMath,
|
||||||
@ -79,7 +80,7 @@ contract MixinPools is
|
|||||||
);
|
);
|
||||||
|
|
||||||
require(
|
require(
|
||||||
_isValidSignature(hashSignedByMaker, makerAddress, makerSignature),
|
_isValidMakerSignature(poolId, makerAddress, makerSignature),
|
||||||
"INVALID_MAKER_SIGNATURE"
|
"INVALID_MAKER_SIGNATURE"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -101,14 +102,32 @@ contract MixinPools is
|
|||||||
_unrecordMaker(poolId, makerAddress);
|
_unrecordMaker(poolId, makerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
function _isValidMakerSignature(bytes32 poolId, address makerAddress, bytes memory makerSignature)
|
||||||
function _isValidMakerSignature(address makerAddress, bytes memory makerSignature)
|
|
||||||
internal
|
internal
|
||||||
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
|
bytes32 approvalHash = _getStakingPoolApprovalMessageHash(poolId, makerAddress);
|
||||||
|
isValid = _isValidSignature(approvalHash, makerAddress, makerSignature);
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getStakingPoolApprovalMessageHash(bytes32 poolId, address makerAddress)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (bytes32 approvalHash)
|
||||||
|
{
|
||||||
|
StakingPoolApproval memory approval = StakingPoolApproval({
|
||||||
|
poolId: poolId,
|
||||||
|
makerAddress: makerAddress
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hash approval message and check signer address
|
||||||
|
address verifierAddress = address(this);
|
||||||
|
approvalHash = LibEIP712Hash._hashStakingPoolApprovalMessage(approval, verifierAddress, CHAIN_ID);
|
||||||
|
|
||||||
|
return approvalHash;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
function _getMakerPoolId(address makerAddress)
|
function _getMakerPoolId(address makerAddress)
|
||||||
internal
|
internal
|
||||||
|
@ -16,10 +16,12 @@ pragma solidity ^0.5.5;
|
|||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "../interfaces/IStructs.sol";
|
import "../interfaces/IStructs.sol";
|
||||||
import "../interfaces/IWallet.sol";
|
import "../interfaces/IWallet.sol";
|
||||||
|
import "../immutable/MixinConstants.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinSignatureValidator is
|
contract MixinSignatureValidator is
|
||||||
IStructs
|
IStructs,
|
||||||
|
MixinConstants
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
|
|
||||||
@ -121,17 +123,7 @@ contract MixinSignatureValidator is
|
|||||||
// Signature verified by wallet contract.
|
// Signature verified by wallet contract.
|
||||||
// If used with an order, the maker of the order is the wallet contract.
|
// If used with an order, the maker of the order is the wallet contract.
|
||||||
} else if (signatureType == SignatureType.Wallet) {
|
} else if (signatureType == SignatureType.Wallet) {
|
||||||
isValid = isValidWalletSignature(
|
isValid = _isValidWalletSignature(
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
);
|
|
||||||
return isValid;
|
|
||||||
|
|
||||||
// Signature verified by wallet contract.
|
|
||||||
// If used with an order, the maker of the order is the wallet contract.
|
|
||||||
} else if (signatureType == SignatureType.Wallet) {
|
|
||||||
isValid = isValidWalletSignature(
|
|
||||||
hash,
|
hash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
@ -153,7 +145,7 @@ contract MixinSignatureValidator is
|
|||||||
/// and defines its own signature verification method.
|
/// and defines its own signature verification method.
|
||||||
/// @param signature Proof that the hash has been signed by signer.
|
/// @param signature Proof that the hash has been signed by signer.
|
||||||
/// @return True if signature is valid for given wallet..
|
/// @return True if signature is valid for given wallet..
|
||||||
function isValidWalletSignature(
|
function _isValidWalletSignature(
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address walletAddress,
|
address walletAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
@ -162,36 +154,28 @@ contract MixinSignatureValidator is
|
|||||||
view
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
|
// contruct hash as bytes, so that it is a valid EIP-1271 payload
|
||||||
|
bytes memory hashAsBytes = new bytes(32);
|
||||||
|
assembly {
|
||||||
|
mstore(add(hashAsBytes, 32), hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static call `isValidSignature` in the destination wallet
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
IWallet(walletAddress).isValidSignature.selector,
|
IWallet(walletAddress).isValidSignature.selector,
|
||||||
hash,
|
hash,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
assembly {
|
(bool success, bytes memory result) = walletAddress.staticcall(callData);
|
||||||
let cdStart := add(callData, 32)
|
|
||||||
let success := staticcall(
|
|
||||||
gas, // forward all gas
|
|
||||||
walletAddress, // address of Wallet contract
|
|
||||||
cdStart, // pointer to start of input
|
|
||||||
mload(callData), // length of input
|
|
||||||
cdStart, // write output over input
|
|
||||||
32 // output size is 32 bytes
|
|
||||||
)
|
|
||||||
|
|
||||||
switch success
|
// Sanity check call and extract the magic value
|
||||||
case 0 {
|
require(
|
||||||
// Revert with `Error("WALLET_ERROR")`
|
success,
|
||||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
"WALLET_ERROR"
|
||||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
);
|
||||||
mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
|
bytes4 magicValue = result.readBytes4(0);
|
||||||
mstore(96, 0)
|
|
||||||
revert(0, 100)
|
isValid = (magicValue == EIP1271_MAGIC_VALUE);
|
||||||
}
|
|
||||||
case 1 {
|
|
||||||
// Signature is valid if call did not revert and returned true
|
|
||||||
isValid := mload(cdStart)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -35,6 +35,9 @@ contract MixinConstants {
|
|||||||
|
|
||||||
uint64 constant public INITIAL_TIMELOCK_PERIOD = INITIAL_EPOCH;
|
uint64 constant public INITIAL_TIMELOCK_PERIOD = INITIAL_EPOCH;
|
||||||
|
|
||||||
|
// bytes4(keccak256("isValidSignature(bytes,bytes)")
|
||||||
|
bytes4 constant internal EIP1271_MAGIC_VALUE = 0x20c13b0b;
|
||||||
|
|
||||||
uint64 constant public EPOCH_PERIOD_IN_SECONDS = 1000; // @TODO SET FOR DEPLOYMENT
|
uint64 constant public EPOCH_PERIOD_IN_SECONDS = 1000; // @TODO SET FOR DEPLOYMENT
|
||||||
|
|
||||||
uint64 constant public TIMELOCK_PERIOD_IN_EPOCHS = 3; // @TODO SET FOR DEPLOYMENT
|
uint64 constant public TIMELOCK_PERIOD_IN_EPOCHS = 3; // @TODO SET FOR DEPLOYMENT
|
||||||
@ -42,4 +45,6 @@ contract MixinConstants {
|
|||||||
uint256 constant public COBB_DOUGLAS_ALPHA_DENOMINATOR = 6; // @TODO SET FOR DEPLOYMENT
|
uint256 constant public COBB_DOUGLAS_ALPHA_DENOMINATOR = 6; // @TODO SET FOR DEPLOYMENT
|
||||||
|
|
||||||
uint256 constant public REWARD_PAYOUT_DELEGATED_STAKE_PERCENT_VALUE = 90; // @TODO SET FOR DEPLOYMENT
|
uint256 constant public REWARD_PAYOUT_DELEGATED_STAKE_PERCENT_VALUE = 90; // @TODO SET FOR DEPLOYMENT
|
||||||
|
|
||||||
|
uint256 constant public CHAIN_ID = 1; // @TODO SET FOR DEPLOYMENT
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,11 @@ interface IStructs {
|
|||||||
NSignatureTypes // 0x05, number of signature types. Always leave at end.
|
NSignatureTypes // 0x05, number of signature types. Always leave at end.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StakingPoolApproval {
|
||||||
|
bytes32 poolId;
|
||||||
|
address makerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
struct Timelock {
|
struct Timelock {
|
||||||
uint64 lockedAt;
|
uint64 lockedAt;
|
||||||
uint96 total;
|
uint96 total;
|
||||||
|
@ -16,15 +16,17 @@ pragma solidity ^0.5.5;
|
|||||||
|
|
||||||
interface IWallet /* is EIP-1271 */ {
|
interface IWallet /* is EIP-1271 */ {
|
||||||
|
|
||||||
/// @dev Verifies that a signature is valid.
|
/// @dev Should return whether the signature provided is valid for the provided data
|
||||||
/// @param hash Message hash that is signed.
|
/// @param data Arbitrary length data signed on the behalf of address(this)
|
||||||
/// @param signature Proof of signing.
|
/// @param signature Signature byte array associated with _data
|
||||||
/// @return The function selector for this function
|
///
|
||||||
|
/// MUST return the bytes4 magic value 0x20c13b0b when function passes.
|
||||||
|
/// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
|
||||||
|
/// MUST allow external calls
|
||||||
function isValidSignature(
|
function isValidSignature(
|
||||||
bytes32 hash,
|
bytes calldata data,
|
||||||
bytes calldata signature
|
bytes calldata signature)
|
||||||
)
|
|
||||||
external
|
external
|
||||||
view
|
view
|
||||||
returns (bytes32 isValidSignatureSelector);
|
returns (bytes4 magicValue);
|
||||||
}
|
}
|
100
contracts/staking/contracts/src/libs/LibEIP712Hash.sol
Normal file
100
contracts/staking/contracts/src/libs/LibEIP712Hash.sol
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
|
||||||
|
import "../interfaces/IStructs.sol";
|
||||||
|
|
||||||
|
|
||||||
|
library LibEIP712Hash
|
||||||
|
{
|
||||||
|
// EIP712 Domain Name value for the Staking contract
|
||||||
|
string constant internal EIP712_STAKING_DOMAIN_NAME = "0x Protocol Staking";
|
||||||
|
|
||||||
|
// EIP712 Domain Version value for the Staking contract
|
||||||
|
string constant internal EIP712_STAKING_DOMAIN_VERSION = "1.0.0";
|
||||||
|
|
||||||
|
// Hash for the EIP712 StakingPool approval message
|
||||||
|
// keccak256(abi.encodePacked(
|
||||||
|
// "StakingPoolApproval(",
|
||||||
|
// "bytes32 poolId,",
|
||||||
|
// "address makerAddress",
|
||||||
|
// ")"
|
||||||
|
// ));
|
||||||
|
bytes32 constant internal EIP712_STAKING_POOL_APPROVAL_SCHEMA_HASH = 0x9b699f12ef1c0f7b43076182dcccc0c548c9a784cfcf27114f98d684e06826b6;
|
||||||
|
|
||||||
|
/// @dev Calculated the EIP712 hash of the StakingPool approval mesasage using the domain separator of this contract.
|
||||||
|
/// @param approval StakingPool approval message containing the transaction hash, transaction signature, and expiration of the approval.
|
||||||
|
/// @return EIP712 hash of the StakingPool approval message with the domain separator of this contract.
|
||||||
|
function _hashStakingPoolApprovalMessage(
|
||||||
|
IStructs.StakingPoolApproval memory approval,
|
||||||
|
address verifierAddress,
|
||||||
|
uint256 chainId
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes32 approvalHash)
|
||||||
|
{
|
||||||
|
approvalHash = _hashEIP712StakingMessage(
|
||||||
|
_hashStakingPoolApproval(approval),
|
||||||
|
verifierAddress,
|
||||||
|
chainId
|
||||||
|
);
|
||||||
|
return approvalHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
|
||||||
|
/// of this contract.
|
||||||
|
/// @param hashStruct The EIP712 hash struct.
|
||||||
|
/// @return EIP712 hash applied to this EIP712 Domain.
|
||||||
|
function _hashEIP712StakingMessage(
|
||||||
|
bytes32 hashStruct,
|
||||||
|
address verifierAddress,
|
||||||
|
uint256 chainId
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes32 result)
|
||||||
|
{
|
||||||
|
bytes32 eip712StakingDomainHash = LibEIP712._hashEIP712Domain(
|
||||||
|
EIP712_STAKING_DOMAIN_NAME,
|
||||||
|
EIP712_STAKING_DOMAIN_VERSION,
|
||||||
|
chainId,
|
||||||
|
verifierAddress
|
||||||
|
);
|
||||||
|
return LibEIP712._hashEIP712Message(eip712StakingDomainHash, hashStruct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calculated the EIP712 hash of the StakingPool approval mesasage with no domain separator.
|
||||||
|
/// @param approval StakingPool approval message containing the transaction hash, transaction signature, and expiration of the approval.
|
||||||
|
/// @return EIP712 hash of the StakingPool approval message with no domain separator.
|
||||||
|
function _hashStakingPoolApproval(IStructs.StakingPoolApproval memory approval)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes32 result)
|
||||||
|
{
|
||||||
|
result = keccak256(abi.encodePacked(
|
||||||
|
EIP712_STAKING_POOL_APPROVAL_SCHEMA_HASH,
|
||||||
|
approval.poolId,
|
||||||
|
approval.makerAddress
|
||||||
|
));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -89,4 +89,20 @@ contract MixinPoolsWrapper is
|
|||||||
makerAddresses = _getMakerAddressesForPool(makerId);
|
makerAddresses = _getMakerAddressesForPool(makerId);
|
||||||
return makerAddresses;
|
return makerAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidMakerSignature(bytes32 poolId, address makerAddress, bytes calldata makerSignature)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bool isValid)
|
||||||
|
{
|
||||||
|
return _isValidMakerSignature(poolId, makerAddress, makerSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStakingPoolApprovalMessageHash(bytes32 poolId, address makerAddress)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes32 approvalHash)
|
||||||
|
{
|
||||||
|
return _getStakingPoolApprovalMessageHash(poolId, makerAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
pragma solidity ^0.5.5;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../core/MixinSignatureValidator.sol";
|
import "../core/MixinSignatureValidator.sol";
|
||||||
|
import "../libs/LibEIP712Hash.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinSignatureValidatorWrapper is
|
contract MixinSignatureValidatorWrapper is
|
||||||
@ -28,9 +29,9 @@ contract MixinSignatureValidatorWrapper is
|
|||||||
function isValidSignature(
|
function isValidSignature(
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
bytes memory signature
|
bytes calldata signature
|
||||||
)
|
)
|
||||||
internal
|
external
|
||||||
view
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
|
40
contracts/staking/contracts/test/TestSignatureValidator.sol
Normal file
40
contracts/staking/contracts/test/TestSignatureValidator.sol
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
|
||||||
|
import "../src/MixinSignatureValidator.sol";
|
||||||
|
import "../src/MixinTransactions.sol";
|
||||||
|
import "../src/MixinExchangeRichErrors.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract TestSignatureValidator is
|
||||||
|
LibEIP712ExchangeDomain,
|
||||||
|
MixinSignatureValidator,
|
||||||
|
MixinTransactions,
|
||||||
|
MixinExchangeRichErrors
|
||||||
|
{
|
||||||
|
|
||||||
|
// solhint-disable no-empty-blocks
|
||||||
|
constructor (uint256 chainId)
|
||||||
|
public
|
||||||
|
LibEIP712ExchangeDomain(chainId, address(0))
|
||||||
|
{}
|
||||||
|
}
|
@ -57,6 +57,7 @@
|
|||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
|
"@0x/utils": "^4.3.1",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^3.0.0",
|
"chai-bignumber": "^3.0.0",
|
||||||
@ -71,12 +72,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.0.5",
|
"@0x/base-contract": "^5.1.0",
|
||||||
"@0x/contracts-utils": "^3.1.1",
|
"@0x/contracts-test-utils": "^3.1.6",
|
||||||
|
"@0x/contracts-utils": "3.1.1",
|
||||||
|
"@0x/order-utils": "^7.2.0",
|
||||||
"@0x/types": "^2.2.2",
|
"@0x/types": "^2.2.2",
|
||||||
"@0x/typescript-typings": "^4.2.2",
|
"@0x/typescript-typings": "^4.2.2",
|
||||||
"@0x/utils": "^4.3.1",
|
"@0x/utils": "^4.3.1",
|
||||||
"@0x/web3-wrapper": "^6.0.5",
|
"@0x/web3-wrapper": "^6.0.6",
|
||||||
"ethereum-types": "^2.1.2",
|
"ethereum-types": "^2.1.2",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
|
@ -29,6 +29,7 @@ describe('Staking Core', () => {
|
|||||||
// constants
|
// constants
|
||||||
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
const ZRX_TOKEN_DECIMALS = new BigNumber(18);
|
||||||
// tokens & addresses
|
// tokens & addresses
|
||||||
|
let accounts: string[];
|
||||||
let owner: string;
|
let owner: string;
|
||||||
let exchange: string;
|
let exchange: string;
|
||||||
let stakers: string[];
|
let stakers: string[];
|
||||||
@ -48,7 +49,7 @@ describe('Staking Core', () => {
|
|||||||
});
|
});
|
||||||
before(async () => {
|
before(async () => {
|
||||||
// create accounts
|
// create accounts
|
||||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
owner = accounts[0];
|
owner = accounts[0];
|
||||||
exchange = accounts[1];
|
exchange = accounts[1];
|
||||||
stakers = accounts.slice(2, 5);
|
stakers = accounts.slice(2, 5);
|
||||||
@ -774,7 +775,7 @@ describe('Staking Core', () => {
|
|||||||
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
|
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('pool management', async() => {
|
it.only('pool management', async() => {
|
||||||
// create first pool
|
// create first pool
|
||||||
const operatorAddress = stakers[0];
|
const operatorAddress = stakers[0];
|
||||||
const operatorShare = 39;
|
const operatorShare = 39;
|
||||||
@ -786,8 +787,15 @@ describe('Staking Core', () => {
|
|||||||
expect(nextPoolId).to.be.equal(expectedNextPoolId);
|
expect(nextPoolId).to.be.equal(expectedNextPoolId);
|
||||||
// add maker to pool
|
// add maker to pool
|
||||||
const makerAddress = makers[0];
|
const makerAddress = makers[0];
|
||||||
const makerSignature = "0x";
|
const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||||
await stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, "0x00", makerSignature, operatorAddress);
|
const makerApproval = stakingWrapper.getSignedApprovalForStakingPool(poolId, makerAddress, makerPrivateKey);
|
||||||
|
|
||||||
|
const onchainHash = await stakingWrapper.getStakingPoolApprovalMessageHashAsync(poolId, makerAddress);
|
||||||
|
console.log(`** ON-CHAIN HASH **\n`, onchainHash);
|
||||||
|
|
||||||
|
console.log(JSON.stringify(makerApproval, null , 4));
|
||||||
|
await stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, "0x00", makerApproval.signature, operatorAddress);
|
||||||
|
throw new Error(`ADDED SUCCESSFULLY!`);
|
||||||
// check the pool id of the maker
|
// check the pool id of the maker
|
||||||
const poolIdOfMaker = await stakingWrapper.getMakerPoolId(makerAddress);
|
const poolIdOfMaker = await stakingWrapper.getMakerPoolId(makerAddress);
|
||||||
expect(poolIdOfMaker).to.be.equal(poolId);
|
expect(poolIdOfMaker).to.be.equal(poolId);
|
||||||
@ -796,15 +804,16 @@ describe('Staking Core', () => {
|
|||||||
expect(makerAddressesForPool).to.be.deep.equal([makerAddress]);
|
expect(makerAddressesForPool).to.be.deep.equal([makerAddress]);
|
||||||
// try to add the same maker address again
|
// try to add the same maker address again
|
||||||
await expectTransactionFailedAsync(
|
await expectTransactionFailedAsync(
|
||||||
stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, "0x00", makerSignature, operatorAddress),
|
stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, "0x00", makerApproval.signature, operatorAddress),
|
||||||
RevertReason.MakerAddressAlreadyRegistered
|
RevertReason.MakerAddressAlreadyRegistered
|
||||||
);
|
);
|
||||||
// try to add a new maker address from an address other than the pool operator
|
// try to add a new maker address from an address other than the pool operator
|
||||||
const notOperatorAddress = owner;
|
const notOperatorAddress = owner;
|
||||||
const anotherMakerAddress = makers[1];
|
const anotherMakerAddress = makers[1];
|
||||||
const anotherMakerSignature = "0x";
|
const anotherMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(anotherMakerAddress)];
|
||||||
|
const anotherMakerApproval = stakingWrapper.getSignedApprovalForStakingPool(poolId, anotherMakerAddress, anotherMakerPrivateKey);
|
||||||
await expectTransactionFailedAsync(
|
await expectTransactionFailedAsync(
|
||||||
stakingWrapper.addMakerToPoolAsync(poolId, anotherMakerAddress, "0x00", anotherMakerSignature, notOperatorAddress),
|
stakingWrapper.addMakerToPoolAsync(poolId, anotherMakerAddress, "0x00", anotherMakerApproval.signature, notOperatorAddress),
|
||||||
RevertReason.OnlyCallableByPoolOperator
|
RevertReason.OnlyCallableByPoolOperator
|
||||||
);
|
);
|
||||||
// try to remove the maker address from an address other than the operator
|
// try to remove the maker address from an address other than the operator
|
||||||
|
42
contracts/staking/test/utils/ApprovalFactory.ts
Normal file
42
contracts/staking/test/utils/ApprovalFactory.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { signingUtils } from '@0x/contracts-test-utils';
|
||||||
|
import { SignatureType } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
|
import { hashUtils } from './hash_utils';
|
||||||
|
import { SignedStakingPoolApproval } from './types';
|
||||||
|
|
||||||
|
export class ApprovalFactory {
|
||||||
|
private readonly _privateKey: Buffer;
|
||||||
|
private readonly _verifyingContractAddress: string;
|
||||||
|
private readonly _chainId: number;
|
||||||
|
|
||||||
|
constructor(privateKey: Buffer, verifyingContractAddress: string, chainId: number) {
|
||||||
|
this._privateKey = privateKey;
|
||||||
|
this._verifyingContractAddress = verifyingContractAddress;
|
||||||
|
this._chainId = chainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public newSignedApproval(
|
||||||
|
poolId: string,
|
||||||
|
makerAddress: string,
|
||||||
|
signatureType: SignatureType = SignatureType.EthSign,
|
||||||
|
): SignedStakingPoolApproval {
|
||||||
|
const approvalHashBuff = hashUtils.getStakingPoolApprovalHashBuffer(
|
||||||
|
poolId,
|
||||||
|
makerAddress,
|
||||||
|
this._verifyingContractAddress,
|
||||||
|
this._chainId
|
||||||
|
);
|
||||||
|
console.log('*** APPROVAL HASH ***\n', approvalHashBuff);
|
||||||
|
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
|
||||||
|
const signedApproval = {
|
||||||
|
makerAddress,
|
||||||
|
poolId,
|
||||||
|
verifyingContractAddress: this._verifyingContractAddress,
|
||||||
|
chainId: this._chainId,
|
||||||
|
signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
|
||||||
|
};
|
||||||
|
return signedApproval;
|
||||||
|
}
|
||||||
|
}
|
@ -10,4 +10,5 @@ export const constants = {
|
|||||||
INITIAL_TIMELOCK_PERIOD: new BigNumber(0),
|
INITIAL_TIMELOCK_PERIOD: new BigNumber(0),
|
||||||
EPOCH_PERIOD_IN_SECONDS: new BigNumber(1000), // @TODO SET FOR DEPLOYMENT*/
|
EPOCH_PERIOD_IN_SECONDS: new BigNumber(1000), // @TODO SET FOR DEPLOYMENT*/
|
||||||
TIMELOCK_PERIOD_IN_EPOCHS: new BigNumber(3), // @TODO SET FOR DEPLOYMENT
|
TIMELOCK_PERIOD_IN_EPOCHS: new BigNumber(3), // @TODO SET FOR DEPLOYMENT
|
||||||
|
CHAIN_ID: 1,
|
||||||
};
|
};
|
32
contracts/staking/test/utils/hash_utils.ts
Normal file
32
contracts/staking/test/utils/hash_utils.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { eip712Utils } from '@0x/order-utils';
|
||||||
|
import { signTypedDataUtils } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
export const hashUtils = {
|
||||||
|
getStakingPoolApprovalHashBuffer(
|
||||||
|
poolId: string,
|
||||||
|
makerAddress: string,
|
||||||
|
verifyingContractAddress: string,
|
||||||
|
chainId: number
|
||||||
|
): Buffer {
|
||||||
|
const typedData = eip712Utils.createStakingPoolApprovalTypedData(
|
||||||
|
poolId,
|
||||||
|
makerAddress,
|
||||||
|
verifyingContractAddress,
|
||||||
|
chainId
|
||||||
|
);
|
||||||
|
const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
|
||||||
|
return hashBuffer;
|
||||||
|
},
|
||||||
|
getStakingPoolApprovalHashHex(
|
||||||
|
poolId: string,
|
||||||
|
makerAddress: string,
|
||||||
|
verifyingContractAddress: string,
|
||||||
|
chainId: number
|
||||||
|
): string {
|
||||||
|
const hashHex = `0x${hashUtils
|
||||||
|
.getStakingPoolApprovalHashBuffer(poolId, makerAddress, verifyingContractAddress, chainId)
|
||||||
|
.toString('hex')}`;
|
||||||
|
return hashHex;
|
||||||
|
},
|
||||||
|
};
|
@ -1,14 +1,18 @@
|
|||||||
import { constants, LogDecoder, txDefaults } from '@0x/contracts-test-utils';
|
import { LogDecoder, txDefaults } from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { assetDataUtils } from '@0x/order-utils';
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { SignatureType } from '@0x/types';
|
||||||
import { LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
import { ERC20ProxyContract } from '@0x/contracts-asset-proxy';
|
import { ERC20ProxyContract } from '@0x/contracts-asset-proxy';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { artifacts, StakingEEventArgs, StakingContract, StakingProxyContract, ZrxVaultContract, RewardVaultContract, LibMathTestContract } from '../../src';
|
import { artifacts, StakingEEventArgs, StakingContract, StakingProxyContract, ZrxVaultContract, RewardVaultContract, LibMathTestContract } from '../../src';
|
||||||
|
import { ApprovalFactory } from './ApprovalFactory';
|
||||||
|
import { SignedStakingPoolApproval } from './types';
|
||||||
|
import { constants } from './constants';
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
@ -272,6 +276,41 @@ export class StakingWrapper {
|
|||||||
const makerAddresses = this.getStakingContract().getMakerAddressesForPool.getABIDecodedReturnData(returndata);
|
const makerAddresses = this.getStakingContract().getMakerAddressesForPool.getABIDecodedReturnData(returndata);
|
||||||
return makerAddresses;
|
return makerAddresses;
|
||||||
}
|
}
|
||||||
|
public async isValidMakerSignatureAsync(poolId: string, makerAddress: string, makerSignature: string): Promise<Boolean> {
|
||||||
|
const calldata = this.getStakingContract().isValidMakerSignature.getABIEncodedTransactionData(poolId, makerAddress, makerSignature);
|
||||||
|
const returndata = await this._callAsync(calldata);
|
||||||
|
const isValid = this.getStakingContract().isValidMakerSignature.getABIDecodedReturnData(returndata);
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
public async getStakingPoolApprovalMessageHashAsync(poolId: string, makerAddress: string): Promise<string> {
|
||||||
|
const calldata = this.getStakingContract().getStakingPoolApprovalMessageHash.getABIEncodedTransactionData(poolId, makerAddress);
|
||||||
|
const returndata = await this._callAsync(calldata);
|
||||||
|
const messageHash = this.getStakingContract().getStakingPoolApprovalMessageHash.getABIDecodedReturnData(returndata);
|
||||||
|
return messageHash;
|
||||||
|
}
|
||||||
|
public getSignedApprovalForStakingPool(poolId: string, makerAddress: string, makerPrivateKey: Buffer, signatureType: SignatureType = SignatureType.EthSign): SignedStakingPoolApproval {
|
||||||
|
const signedStakingPoolApproval = this.getSignedApprovalForStakingPoolFlexible(
|
||||||
|
poolId,
|
||||||
|
makerAddress,
|
||||||
|
makerPrivateKey,
|
||||||
|
this.getStakingProxyContract().address,
|
||||||
|
constants.CHAIN_ID,
|
||||||
|
signatureType
|
||||||
|
);
|
||||||
|
return signedStakingPoolApproval;
|
||||||
|
}
|
||||||
|
public getSignedApprovalForStakingPoolFlexible(
|
||||||
|
poolId: string,
|
||||||
|
makerAddress: string,
|
||||||
|
makerPrivateKey: Buffer,
|
||||||
|
verifierAddress: string,
|
||||||
|
chainId: number,
|
||||||
|
signatureType: SignatureType = SignatureType.EthSign,
|
||||||
|
): SignedStakingPoolApproval {
|
||||||
|
const approvalFactory = new ApprovalFactory(makerPrivateKey, verifierAddress, chainId);
|
||||||
|
const signedStakingPoolApproval = approvalFactory.newSignedApproval(poolId, makerAddress, signatureType);
|
||||||
|
return signedStakingPoolApproval;
|
||||||
|
}
|
||||||
///// EPOCHS /////
|
///// EPOCHS /////
|
||||||
public async goToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
|
public async goToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const calldata = this.getStakingContract().finalizeFees.getABIEncodedTransactionData();
|
const calldata = this.getStakingContract().finalizeFees.getABIEncodedTransactionData();
|
||||||
|
12
contracts/staking/test/utils/types.ts
Normal file
12
contracts/staking/test/utils/types.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
export interface StakingPoolApproval {
|
||||||
|
makerAddress: string,
|
||||||
|
poolId: string,
|
||||||
|
verifyingContractAddress: string,
|
||||||
|
chainId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SignedStakingPoolApproval extends StakingPoolApproval {
|
||||||
|
signature: string;
|
||||||
|
}
|
@ -149,6 +149,15 @@ export const constants = {
|
|||||||
{ name: 'approvalExpirationTimeSeconds', type: 'uint256' },
|
{ name: 'approvalExpirationTimeSeconds', type: 'uint256' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
STAKING_DOMAIN_NAME: '0x Protocol Staking',
|
||||||
|
STAKING_DOMAIN_VERSION: '1.0.0',
|
||||||
|
STAKING_POOL_APPROVAL_SCHEMA: {
|
||||||
|
name: 'StakingPoolApproval',
|
||||||
|
parameters: [
|
||||||
|
{ name: 'poolId', type: 'bytes32' },
|
||||||
|
{ name: 'makerAddress', type: 'address' },
|
||||||
|
],
|
||||||
|
},
|
||||||
ERC20_METHOD_ABI,
|
ERC20_METHOD_ABI,
|
||||||
ERC721_METHOD_ABI,
|
ERC721_METHOD_ABI,
|
||||||
MULTI_ASSET_METHOD_ABI,
|
MULTI_ASSET_METHOD_ABI,
|
||||||
|
@ -125,4 +125,34 @@ export const eip712Utils = {
|
|||||||
);
|
);
|
||||||
return typedData;
|
return typedData;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Creates an Coordiantor typedData EIP712TypedData object for use with the Coordinator extension contract
|
||||||
|
* @return A typed data object
|
||||||
|
*/
|
||||||
|
createStakingPoolApprovalTypedData: (
|
||||||
|
poolId: string,
|
||||||
|
makerAddress: string,
|
||||||
|
verifyingContractAddress: string,
|
||||||
|
chainId: number
|
||||||
|
): EIP712TypedData => {
|
||||||
|
const domain = {
|
||||||
|
name: constants.STAKING_DOMAIN_NAME,
|
||||||
|
version: constants.STAKING_DOMAIN_VERSION,
|
||||||
|
verifyingContractAddress,
|
||||||
|
chainId
|
||||||
|
};
|
||||||
|
const approval = {
|
||||||
|
poolId,
|
||||||
|
makerAddress,
|
||||||
|
};
|
||||||
|
const typedData = eip712Utils.createTypedData(
|
||||||
|
constants.STAKING_POOL_APPROVAL_SCHEMA.name,
|
||||||
|
{
|
||||||
|
StakingPoolApproval: constants.STAKING_POOL_APPROVAL_SCHEMA.parameters,
|
||||||
|
},
|
||||||
|
approval,
|
||||||
|
domain,
|
||||||
|
);
|
||||||
|
return typedData;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -69,6 +69,8 @@ export const signTypedDataUtils = {
|
|||||||
let deps = signTypedDataUtils._findDependencies(primaryType, types);
|
let deps = signTypedDataUtils._findDependencies(primaryType, types);
|
||||||
deps = deps.filter(d => d !== primaryType);
|
deps = deps.filter(d => d !== primaryType);
|
||||||
deps = [primaryType].concat(deps.sort());
|
deps = [primaryType].concat(deps.sort());
|
||||||
|
console.log('*** DEPS ****\n', JSON.stringify(deps, null, 4));
|
||||||
|
console.log('*** TYPES ****\n', JSON.stringify(types, null, 4));
|
||||||
let result = '';
|
let result = '';
|
||||||
for (const dep of deps) {
|
for (const dep of deps) {
|
||||||
result += `${dep}(${types[dep].map(({ name, type }) => `${type} ${name}`).join(',')})`;
|
result += `${dep}(${types[dep].map(({ name, type }) => `${type} ${name}`).join(',')})`;
|
||||||
|
49
yarn.lock
49
yarn.lock
@ -649,6 +649,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@0x/base-contract" "^4.0.3"
|
"@0x/base-contract" "^4.0.3"
|
||||||
|
|
||||||
|
"@0x/abi-gen-wrappers@^4.2.0":
|
||||||
|
version "4.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@0x/abi-gen-wrappers/-/abi-gen-wrappers-4.3.0.tgz#b36616b129f44072474a7d5739299e4b1068e3d4"
|
||||||
|
integrity sha512-KnpoHbbqfidECl4hTGOvBaCj1N3LASHcdNO38yOMo1eO4B0H+kuyDVFjN3nbNt7lnXTPJ+DdaQpoDVQwySdEDQ==
|
||||||
|
dependencies:
|
||||||
|
"@0x/base-contract" "^5.1.0"
|
||||||
|
|
||||||
"@0x/abi-gen@^2.0.9":
|
"@0x/abi-gen@^2.0.9":
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@0x/abi-gen/-/abi-gen-2.1.1.tgz#2ca9072e64a2a46b6149aaea434f09d5dbf0866f"
|
resolved "https://registry.yarnpkg.com/@0x/abi-gen/-/abi-gen-2.1.1.tgz#2ca9072e64a2a46b6149aaea434f09d5dbf0866f"
|
||||||
@ -697,13 +704,13 @@
|
|||||||
ethers "~4.0.4"
|
ethers "~4.0.4"
|
||||||
lodash "^4.17.11"
|
lodash "^4.17.11"
|
||||||
|
|
||||||
"@0x/contract-addresses@^2.2.1":
|
"@0x/contract-addresses@^2.2.1", "@0x/contract-addresses@^2.3.1":
|
||||||
version "2.3.3"
|
version "2.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-2.3.3.tgz#8cf009e7668c2fccca416177c85f3f6612c724c6"
|
resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-2.3.3.tgz#8cf009e7668c2fccca416177c85f3f6612c724c6"
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.11"
|
lodash "^4.17.11"
|
||||||
|
|
||||||
"@0x/contract-artifacts@^1.3.0":
|
"@0x/contract-artifacts@^1.3.0", "@0x/contract-artifacts@^1.5.0":
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.npmjs.org/@0x/contract-artifacts/-/contract-artifacts-1.5.1.tgz#6fba56a1d3e2d5d897a75fcfa432e49e2ebb17a7"
|
resolved "https://registry.npmjs.org/@0x/contract-artifacts/-/contract-artifacts-1.5.1.tgz#6fba56a1d3e2d5d897a75fcfa432e49e2ebb17a7"
|
||||||
|
|
||||||
@ -746,6 +753,21 @@
|
|||||||
ethereumjs-util "^5.1.1"
|
ethereumjs-util "^5.1.1"
|
||||||
lodash "^4.17.5"
|
lodash "^4.17.5"
|
||||||
|
|
||||||
|
"@0x/contracts-utils@3.1.1":
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@0x/contracts-utils/-/contracts-utils-3.1.1.tgz#d3d70ec4f5f9e10d85abc7d0c1b2b7bb34f38927"
|
||||||
|
dependencies:
|
||||||
|
"@0x/base-contract" "^5.0.5"
|
||||||
|
"@0x/order-utils" "^7.2.0"
|
||||||
|
"@0x/types" "^2.2.2"
|
||||||
|
"@0x/typescript-typings" "^4.2.2"
|
||||||
|
"@0x/utils" "^4.3.1"
|
||||||
|
"@0x/web3-wrapper" "^6.0.5"
|
||||||
|
bn.js "^4.11.8"
|
||||||
|
ethereum-types "^2.1.2"
|
||||||
|
ethereumjs-util "^5.1.1"
|
||||||
|
lodash "^4.17.11"
|
||||||
|
|
||||||
"@0x/coordinator-server@^0.1.3":
|
"@0x/coordinator-server@^0.1.3":
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.1.3.tgz#5fbb7c11bb641aa5386797769cab9a68a7d15b79"
|
resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.1.3.tgz#5fbb7c11bb641aa5386797769cab9a68a7d15b79"
|
||||||
@ -797,6 +819,29 @@
|
|||||||
ethers "~4.0.4"
|
ethers "~4.0.4"
|
||||||
lodash "^4.17.11"
|
lodash "^4.17.11"
|
||||||
|
|
||||||
|
"@0x/order-utils@^7.2.0":
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-7.2.0.tgz#c73d81e3225e9ec7736f9789e14388c9fe2b831c"
|
||||||
|
integrity sha512-P1tVRKyUvfU/yjYS+bbK+InZr0V2wPlX7nTp6ORTuPWd5zjWrRN7rpq50qvgY+UZCeajcQh9g4Dt1l+LWot/AA==
|
||||||
|
dependencies:
|
||||||
|
"@0x/abi-gen-wrappers" "^4.2.0"
|
||||||
|
"@0x/assert" "^2.0.9"
|
||||||
|
"@0x/base-contract" "^5.0.5"
|
||||||
|
"@0x/contract-addresses" "^2.3.1"
|
||||||
|
"@0x/contract-artifacts" "^1.5.0"
|
||||||
|
"@0x/json-schemas" "^3.0.9"
|
||||||
|
"@0x/types" "^2.2.2"
|
||||||
|
"@0x/typescript-typings" "^4.2.2"
|
||||||
|
"@0x/utils" "^4.3.1"
|
||||||
|
"@0x/web3-wrapper" "^6.0.5"
|
||||||
|
"@types/node" "*"
|
||||||
|
bn.js "^4.11.8"
|
||||||
|
ethereum-types "^2.1.2"
|
||||||
|
ethereumjs-abi "0.6.5"
|
||||||
|
ethereumjs-util "^5.1.1"
|
||||||
|
ethers "~4.0.4"
|
||||||
|
lodash "^4.17.11"
|
||||||
|
|
||||||
"@0x/subproviders@^4.1.1":
|
"@0x/subproviders@^4.1.1":
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-4.1.2.tgz#ab7bb0f482b11ccb4615fb5dd8ca85199cd0ae23"
|
resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-4.1.2.tgz#ab7bb0f482b11ccb4615fb5dd8ca85199cd0ae23"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user