ZeroEx: TransformERC20, TokenSpender (#2545)
* `@0x/contracts-utils`: Convert more 0.6 contracts * `@0x/contracts-erc20`: Add solidity 0.6 contracts. * `@0x/utils`: Add new `ZeroExRevertErrors` revert types * `@0x/contracts-zero-ex`: Introduce the `TransformERC20` feature. * `@0x/subproviders`: Update ganache-core. `@0x/web3-wrapper`: Update ganache-core. * `@0x/contracts-zero-ex`: Make `TokenSpender`'s puppet contract a distinct contract type and rename `getTokenSpenderPuppet()` to `getAllowanceTarget()` * `@0x/zero-ex`: Rebase and use "slot" instead of "offset" language in storage buckets. * `@0x/web3-wrapper`: Add `getAccountNonceAsync()` to `Web3Wrapper` * `@0x/contracts-zero-ex`: Revamp TransformERC20. * `@0x/contracts-zero-ex`: Remove `payable` from `IERC20Transformer.transform()` and disable hex capitalization linter rule because of prettier conflicts. * `@0x/contracts-zero-ex`: Use `immutable` owner in `Puppet` instead of `Ownable`. * `@x/utils`: Address review feedback. * `@0x/contracts-zero-ex`: Address review feedback. * `@0x/contracts-utils`: Address review feedback. * `@0x/contracts-zero-ex`: Return deployment nonce in `transform()`. * `@0x/contracts-zero-ex`: Finish returning deployment nonce in `transform()`. * `@0x/contracts-zero-ex`: Fix doc-gen bug. * `@0x/contracts-zero-ex`: Address review comments. * `@0x/utils`: Add `NegativeTransformERC20OutputERror` * `@0x/contracts-zero-ex`: Revert if the taker's output amount decreases. Co-authored-by: Lawrence Forman <me@merklejerk.com>
This commit is contained in:
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "6.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update ganache-core",
|
||||
"pr": 2545
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582623685,
|
||||
"version": "6.0.8",
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"ethereum-types": "^3.1.0",
|
||||
"ethereumjs-tx": "^1.3.5",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ganache-core": "^2.9.0-istanbul.0",
|
||||
"ganache-core": "^2.10.2",
|
||||
"hdkey": "^0.7.1",
|
||||
"json-rpc-error": "2.0.0",
|
||||
"lodash": "^4.17.11",
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
{
|
||||
"note": "`instanceof Array` => `Array.isArray`",
|
||||
"pr": 2567
|
||||
},
|
||||
{
|
||||
"note": "Add more `ZeroExRevertErrors`",
|
||||
"pr": 2545
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -49,4 +49,7 @@ export const ZeroExRevertErrors = {
|
||||
Proxy: require('./revert_errors/zero-ex/proxy_revert_errors'),
|
||||
SimpleFunctionRegistry: require('./revert_errors/zero-ex/simple_function_registry_revert_errors'),
|
||||
Ownable: require('./revert_errors/zero-ex/ownable_revert_errors'),
|
||||
Spender: require('./revert_errors/zero-ex/spender_revert_errors'),
|
||||
TransformERC20: require('./revert_errors/zero-ex/transform_erc20_revert_errors'),
|
||||
Wallet: require('./revert_errors/zero-ex/wallet_revert_errors'),
|
||||
};
|
||||
|
||||
@@ -9,7 +9,16 @@ import { BigNumber } from './configured_bignumber';
|
||||
|
||||
// tslint:disable: max-classes-per-file
|
||||
|
||||
type ArgTypes = string | BigNumber | number | boolean | BigNumber[] | string[] | number[] | boolean[];
|
||||
type ArgTypes =
|
||||
| string
|
||||
| BigNumber
|
||||
| number
|
||||
| boolean
|
||||
| BigNumber[]
|
||||
| string[]
|
||||
| number[]
|
||||
| boolean[]
|
||||
| Array<BigNumber | number | string>;
|
||||
type ValueMap = ObjectMap<ArgTypes | undefined>;
|
||||
type RevertErrorDecoder = (hex: string) => ValueMap;
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@ export class OnlyCallableBySelfError extends RevertError {
|
||||
}
|
||||
}
|
||||
|
||||
// This is identical to the one in utils.
|
||||
// export class IllegalReentrancyError extends RevertError {
|
||||
// constructor() {
|
||||
// super('IllegalReentrancyError', 'IllegalReentrancyError()', {});
|
||||
// }
|
||||
// }
|
||||
|
||||
const types = [OnlyCallableBySelfError];
|
||||
|
||||
// Register the types we've defined.
|
||||
|
||||
@@ -16,7 +16,23 @@ export class MigrateCallFailedError extends RevertError {
|
||||
}
|
||||
}
|
||||
|
||||
const types = [AlreadyMigratingError, MigrateCallFailedError];
|
||||
export class OnlyOwnerError extends RevertError {
|
||||
constructor(sender?: string, owner?: string) {
|
||||
super('OnlyOwnerError', 'OnlyOwnerError(address sender, bytes owner)', {
|
||||
sender,
|
||||
owner,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// This is identical to the one in utils.
|
||||
// export class TransferOwnerToZeroError extends RevertError {
|
||||
// constructor() {
|
||||
// super('TransferOwnerToZeroError', 'TransferOwnerToZeroError()', {});
|
||||
// }
|
||||
// }
|
||||
|
||||
const types = [AlreadyMigratingError, MigrateCallFailedError, OnlyOwnerError];
|
||||
|
||||
// Register the types we've defined.
|
||||
for (const type of types) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { RevertError } from '../../revert_error';
|
||||
import { Numberish } from '../../types';
|
||||
|
||||
// tslint:disable:max-classes-per-file
|
||||
export class SpenderERC20TransferFromFailedError extends RevertError {
|
||||
constructor(token?: string, owner?: string, to?: string, amount?: Numberish, errorData?: string) {
|
||||
super(
|
||||
'SpenderERC20TransferFromFailedError',
|
||||
'SpenderERC20TransferFromFailedError(address token, address owner, address to, uint256 amount, bytes errorData)',
|
||||
{
|
||||
token,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
errorData,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const types = [SpenderERC20TransferFromFailedError];
|
||||
|
||||
// Register the types we've defined.
|
||||
for (const type of types) {
|
||||
RevertError.registerType(type);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import { RevertError } from '../../revert_error';
|
||||
import { Numberish } from '../../types';
|
||||
|
||||
// tslint:disable:max-classes-per-file
|
||||
export class InsufficientEthAttachedError extends RevertError {
|
||||
constructor(ethAttached?: Numberish, ethNeeded?: Numberish) {
|
||||
super('InsufficientEthAttachedError', 'InsufficientEthAttachedError(uint256 ethAttached, uint256 ethNeeded)', {
|
||||
ethAttached,
|
||||
ethNeeded,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class IncompleteTransformERC20Error extends RevertError {
|
||||
constructor(outputToken?: string, outputTokenAmount?: Numberish, minOutputTokenAmount?: Numberish) {
|
||||
super(
|
||||
'IncompleteTransformERC20Error',
|
||||
'IncompleteTransformERC20Error(address outputToken, uint256 outputTokenAmount, uint256 minOutputTokenAmount)',
|
||||
{
|
||||
outputToken,
|
||||
outputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class NegativeTransformERC20OutputError extends RevertError {
|
||||
constructor(outputToken?: string, outputTokenLostAmount?: Numberish) {
|
||||
super(
|
||||
'NegativeTransformERC20OutputError',
|
||||
'NegativeTransformERC20OutputError(address outputToken, uint256 outputTokenLostAmount)',
|
||||
{
|
||||
outputToken,
|
||||
outputTokenLostAmount,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedTransformerError extends RevertError {
|
||||
constructor(transformer?: string, rlpNonce?: string) {
|
||||
super('UnauthorizedTransformerError', 'UnauthorizedTransformerError(address transformer, bytes rlpNonce)', {
|
||||
transformer,
|
||||
rlpNonce,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidRLPNonceError extends RevertError {
|
||||
constructor(rlpNonce?: string) {
|
||||
super('InvalidRLPNonceError', 'InvalidRLPNonceError(bytes rlpNonce)', { rlpNonce });
|
||||
}
|
||||
}
|
||||
|
||||
export class IncompleteFillSellQuoteError extends RevertError {
|
||||
constructor(sellToken?: string, soldAmount?: Numberish, sellAmount?: Numberish) {
|
||||
super(
|
||||
'IncompleteFillSellQuoteError',
|
||||
'IncompleteFillSellQuoteError(address sellToken, address[] soldAmount, uint256[] sellAmount)',
|
||||
{
|
||||
sellToken,
|
||||
soldAmount,
|
||||
sellAmount,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class IncompleteFillBuyQuoteError extends RevertError {
|
||||
constructor(buyToken?: string, boughtAmount?: Numberish, buyAmount?: Numberish) {
|
||||
super(
|
||||
'IncompleteFillBuyQuoteError',
|
||||
'IncompleteFillBuyQuoteError(address buyToken, address[] boughtAmount, uint256[] buyAmount)',
|
||||
{
|
||||
buyToken,
|
||||
boughtAmount,
|
||||
buyAmount,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class InsufficientTakerTokenError extends RevertError {
|
||||
constructor(tokenBalance?: Numberish, tokensNeeded?: Numberish) {
|
||||
super(
|
||||
'InsufficientTakerTokenError',
|
||||
'InsufficientTakerTokenError(uint256 tokenBalance, uint256 tokensNeeded)',
|
||||
{
|
||||
tokenBalance,
|
||||
tokensNeeded,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class InsufficientProtocolFeeError extends RevertError {
|
||||
constructor(ethBalance?: Numberish, ethNeeded?: Numberish) {
|
||||
super('InsufficientProtocolFeeError', 'InsufficientProtocolFeeError(uint256 ethBalance, uint256 ethNeeded)', {
|
||||
ethBalance,
|
||||
ethNeeded,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidERC20AssetDataError extends RevertError {
|
||||
constructor(assetData?: string) {
|
||||
super('InvalidERC20AssetDataError', 'InvalidERC20AssetDataError(bytes assetData)', {
|
||||
assetData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class WrongNumberOfTokensReceivedError extends RevertError {
|
||||
constructor(actual?: Numberish, expected?: Numberish) {
|
||||
super(
|
||||
'WrongNumberOfTokensReceivedError',
|
||||
'WrongNumberOfTokensReceivedError(uint256 actual, uint256 expected)',
|
||||
{
|
||||
actual,
|
||||
expected,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidTokenReceivedError extends RevertError {
|
||||
constructor(token?: string) {
|
||||
super('InvalidTokenReceivedError', 'InvalidTokenReceivedError(address token)', {
|
||||
token,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const types = [
|
||||
InsufficientEthAttachedError,
|
||||
IncompleteTransformERC20Error,
|
||||
NegativeTransformERC20OutputError,
|
||||
UnauthorizedTransformerError,
|
||||
InvalidRLPNonceError,
|
||||
IncompleteFillSellQuoteError,
|
||||
IncompleteFillBuyQuoteError,
|
||||
InsufficientTakerTokenError,
|
||||
InsufficientProtocolFeeError,
|
||||
InvalidERC20AssetDataError,
|
||||
WrongNumberOfTokensReceivedError,
|
||||
InvalidTokenReceivedError,
|
||||
];
|
||||
|
||||
// Register the types we've defined.
|
||||
for (const type of types) {
|
||||
RevertError.registerType(type);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { RevertError } from '../../revert_error';
|
||||
import { Numberish } from '../../types';
|
||||
|
||||
// tslint:disable:max-classes-per-file
|
||||
export class WalletExecuteCallFailedError extends RevertError {
|
||||
constructor(wallet?: string, callTarget?: string, callData?: string, callValue?: Numberish, errorData?: string) {
|
||||
super(
|
||||
'WalletExecuteCallFailedError',
|
||||
'WalletExecuteCallFailedError(address wallet, address callTarget, bytes callData, uint256 callValue, bytes errorData)',
|
||||
{
|
||||
wallet,
|
||||
callTarget,
|
||||
callData,
|
||||
callValue,
|
||||
errorData,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class WalletExecuteDelegateCallFailedError extends RevertError {
|
||||
constructor(wallet?: string, callTarget?: string, callData?: string, errorData?: string) {
|
||||
super(
|
||||
'WalletExecuteDelegateCallFailedError',
|
||||
'WalletExecuteDelegateCallFailedError(address wallet, address callTarget, bytes callData, bytes errorData)',
|
||||
{
|
||||
wallet,
|
||||
callTarget,
|
||||
callData,
|
||||
errorData,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const types = [WalletExecuteCallFailedError, WalletExecuteDelegateCallFailedError];
|
||||
|
||||
// Register the types we've defined.
|
||||
for (const type of types) {
|
||||
RevertError.registerType(type);
|
||||
}
|
||||
@@ -1,4 +1,17 @@
|
||||
[
|
||||
{
|
||||
"version": "7.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `getAccountNonce()` to `Web3Wrapper`",
|
||||
"pr": 2545
|
||||
},
|
||||
{
|
||||
"note": "Update ganache-core",
|
||||
"pr": 2545
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582623685,
|
||||
"version": "7.0.7",
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ganache-core": "^2.9.0-istanbul.0",
|
||||
"ganache-core": "^2.10.2",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
|
||||
@@ -360,6 +360,27 @@ export class Web3Wrapper {
|
||||
const blockNumber = utils.convertHexToNumberOrNull(blockNumberHex);
|
||||
return blockNumber as number;
|
||||
}
|
||||
/**
|
||||
* Fetches the nonce for an account (transaction count for EOAs).
|
||||
* @param address Address of account.
|
||||
* @param defaultBlock Block height at which to make the call. Defaults to `latest`
|
||||
* @returns Account nonce.
|
||||
*/
|
||||
public async getAccountNonceAsync(address: string, defaultBlock?: BlockParam): Promise<number> {
|
||||
assert.isETHAddressHex('address', address);
|
||||
if (defaultBlock !== undefined) {
|
||||
Web3Wrapper._assertBlockParam(defaultBlock);
|
||||
}
|
||||
const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
|
||||
const encodedAddress = marshaller.marshalAddress(address);
|
||||
const nonceHex = await this.sendRawPayloadAsync<string>({
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [encodedAddress, marshalledDefaultBlock],
|
||||
});
|
||||
assert.isHexString('nonce', nonceHex);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
return parseInt(nonceHex.substr(2), 16);
|
||||
}
|
||||
/**
|
||||
* Fetch a specific Ethereum block without transaction data
|
||||
* @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral)
|
||||
|
||||
@@ -35,8 +35,7 @@ describe('Web3Wrapper tests', () => {
|
||||
describe('#getNodeVersionAsync', () => {
|
||||
it('gets the node version', async () => {
|
||||
const nodeVersion = await web3Wrapper.getNodeVersionAsync();
|
||||
const NODE_VERSION = 'EthereumJS TestRPC/v2.9.0-istanbul.0/ethereum-js';
|
||||
expect(nodeVersion).to.be.equal(NODE_VERSION);
|
||||
expect(nodeVersion).to.be.match(/EthereumJS TestRPC\/.+\/ethereum-js$/);
|
||||
});
|
||||
});
|
||||
describe('#getNetworkIdAsync', () => {
|
||||
|
||||
Reference in New Issue
Block a user