Merge branch 'v2-prototype' into feature/combinatorial-testing
* v2-prototype: (68 commits) Stop exporting ArtifactWriter Fix no-unused-variable tslint rule to include parameters and fix issues Fix linter exclude rule Validate all signature types rather then only ECSignatures Store the instantiated OrderValidationUtils Remove global hooks from tests and deploy contracts from within the specific tests Add EmitStatement to ASTVisitor Fix tslint issues Add back artifacts file Fix a bug in SolCompilerArtifacts adapter config overriding Move OrderValidationUtils (+ tests) and ExchangeTransferSimulator to order-utils export parseECSignature method Export ArtifactWriter from migrations package Remove unused artifact file Pass in generated contract wrapper to orderValidationUtils at instantiation Refactor orderValidationUtils to use the generated contract wrapper instead of the higher-level one Refactor ExchangeTransferSimulator public interface to accet an AbstractBalanceAndProxyAllowanceLazyStore so that this module could be re-used in different contexts. Increase timeout for contract migrations Remove some copy-paste code Await transactions in migrations ...
This commit is contained in:
@@ -35,7 +35,28 @@ jobs:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo
|
||||
test-1:
|
||||
test-contracts-ganache:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci contracts
|
||||
test-contracts-geth:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
- image: albrow/0x-devnet
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
# HACK(albrow): we need to sleep 15 seconds to ensure the devnet is
|
||||
# initialized
|
||||
- run: sleep 15 && TEST_PROVIDER=geth yarn wsrun test contracts
|
||||
test-rest:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
@@ -45,6 +66,13 @@ jobs:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0xproject/contract-wrappers
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-compiler
|
||||
- run: yarn wsrun test:circleci @0xproject/assert
|
||||
- run: yarn wsrun test:circleci @0xproject/connect
|
||||
- run: yarn wsrun test:circleci @0xproject/dev-utils
|
||||
- run: yarn wsrun test:circleci @0xproject/json-schemas
|
||||
- run: yarn wsrun test:circleci @0xproject/subproviders
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-cov
|
||||
- run: yarn wsrun test:circleci @0xproject/metacoin
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
@@ -53,30 +81,6 @@ jobs:
|
||||
key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-compiler/coverage/lcov.info
|
||||
test-contracts:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci contracts
|
||||
test-2:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0xproject/assert
|
||||
- run: yarn wsrun test:circleci @0xproject/connect
|
||||
- run: yarn wsrun test:circleci @0xproject/dev-utils
|
||||
- run: yarn wsrun test:circleci @0xproject/json-schemas
|
||||
- run: yarn wsrun test:circleci @0xproject/subproviders
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-cov
|
||||
- run: yarn wsrun test:circleci @0xproject/metacoin
|
||||
- save_cache:
|
||||
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
@@ -162,13 +166,13 @@ workflows:
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- test-1:
|
||||
- test-contracts-ganache:
|
||||
requires:
|
||||
- build
|
||||
- test-2:
|
||||
- test-contracts-geth:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts:
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
- static-tests:
|
||||
@@ -176,5 +180,4 @@ workflows:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-1
|
||||
- test-2
|
||||
- test-rest
|
||||
|
@@ -21,7 +21,7 @@
|
||||
"pre_build": "run-s generate_contract_wrappers copy_artifacts",
|
||||
"copy_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrapper/**/*",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*",
|
||||
"test:circleci": "run-s test:coverage",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
|
@@ -37,7 +37,7 @@ export class BaseContract {
|
||||
protected static _lowercaseAddress(type: string, value: string): string {
|
||||
return type === 'address' ? value.toLowerCase() : value;
|
||||
}
|
||||
protected static _bigNumberToString(type: string, value: any): any {
|
||||
protected static _bigNumberToString(_type: string, value: any): any {
|
||||
return _.isObject(value) && value.isBigNumber ? value.toString() : value;
|
||||
}
|
||||
protected static _lookupConstructorAbi(abi: ContractAbi): ConstructorAbi {
|
||||
@@ -60,7 +60,7 @@ export class BaseContract {
|
||||
return defaultConstructorAbi;
|
||||
}
|
||||
}
|
||||
protected static _bnToBigNumber(type: string, value: any): any {
|
||||
protected static _bnToBigNumber(_type: string, value: any): any {
|
||||
return _.isObject(value) && value._bn ? new BigNumber(value.toString()) : value;
|
||||
}
|
||||
protected static async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>(
|
||||
|
@@ -48,7 +48,7 @@ export class HttpClient implements Client {
|
||||
return '';
|
||||
}
|
||||
// format params into a form the api expects
|
||||
const formattedParams = _.mapKeys(params, (value: any, key: string) => {
|
||||
const formattedParams = _.mapKeys(params, (_value: any, key: string) => {
|
||||
return _.get(OPTS_TO_QUERY_FIELD_MAP, key, key);
|
||||
});
|
||||
// stringify the formatted object
|
||||
|
@@ -78,7 +78,7 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
connection.on(WebsocketConnectionEventType.Error, wsError => {
|
||||
handler.onError(this, subscriptionOpts, wsError);
|
||||
});
|
||||
connection.on(WebsocketConnectionEventType.Close, (code: number, desc: string) => {
|
||||
connection.on(WebsocketConnectionEventType.Close, (_code: number, _desc: string) => {
|
||||
handler.onClose(this, subscriptionOpts);
|
||||
});
|
||||
connection.on(WebsocketConnectionEventType.Message, message => {
|
||||
|
@@ -0,0 +1,11 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void;
|
||||
public abstract deleteBalance(tokenAddress: string, userAddress: string): void;
|
||||
public abstract setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void;
|
||||
public abstract deleteProxyAllowance(tokenAddress: string, userAddress: string): void;
|
||||
public abstract deleteAll(): void;
|
||||
}
|
@@ -18,6 +18,7 @@ import * as _ from 'lodash';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher';
|
||||
import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||
import {
|
||||
BlockRange,
|
||||
EventCallback,
|
||||
@@ -54,7 +55,7 @@ interface ExchangeContractErrCodesToMsgs {
|
||||
*/
|
||||
export class ExchangeWrapper extends ContractWrapper {
|
||||
private _exchangeContractIfExists?: ExchangeContract;
|
||||
private _orderValidationUtils: OrderValidationUtils;
|
||||
private _orderValidationUtilsIfExists?: OrderValidationUtils;
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = {
|
||||
[ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
|
||||
@@ -75,7 +76,6 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
) {
|
||||
super(web3Wrapper, networkId);
|
||||
this._tokenWrapper = tokenWrapper;
|
||||
this._orderValidationUtils = new OrderValidationUtils(this);
|
||||
this._contractAddressIfExists = contractAddressIfExists;
|
||||
this._zrxContractAddressIfExists = zrxContractAddressIfExists;
|
||||
}
|
||||
@@ -177,8 +177,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -252,9 +257,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
if (shouldValidate) {
|
||||
let filledTakerTokenAmount = new BigNumber(0);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const signedOrder of signedOrders) {
|
||||
const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const singleFilledTakerTokenAmount = await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount.minus(filledTakerTokenAmount),
|
||||
@@ -345,9 +355,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
@@ -421,8 +436,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -483,9 +503,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
@@ -733,8 +758,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
zrxTokenAddress,
|
||||
@@ -759,8 +789,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -806,8 +841,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -917,6 +957,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
||||
return orderHashHex;
|
||||
}
|
||||
private async _getOrderValidationUtilsAsync(): Promise<OrderValidationUtils> {
|
||||
if (!_.isUndefined(this._orderValidationUtilsIfExists)) {
|
||||
return this._orderValidationUtilsIfExists;
|
||||
}
|
||||
const exchangeContract = await this._getExchangeContractAsync();
|
||||
this._orderValidationUtilsIfExists = new OrderValidationUtils(exchangeContract);
|
||||
return this._orderValidationUtilsIfExists;
|
||||
}
|
||||
// tslint:enable:no-unused-variable
|
||||
private async _getExchangeContractAsync(): Promise<ExchangeContract> {
|
||||
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
|
||||
/**
|
||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||
*/
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceFetcher {
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
private _defaultBlock: BlockParamLiteral;
|
||||
private _balance: {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../types';
|
||||
import { constants } from '../utils/constants';
|
||||
|
||||
@@ -35,8 +35,7 @@ const ERR_MSG_MAPPING = {
|
||||
};
|
||||
|
||||
export class ExchangeTransferSimulator {
|
||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private _store: AbstractBalanceAndProxyAllowanceLazyStore;
|
||||
private static _throwValidationError(
|
||||
failureReason: FailureReason,
|
||||
tradeSide: TradeSide,
|
||||
@@ -45,9 +44,8 @@ export class ExchangeTransferSimulator {
|
||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) {
|
||||
this._store = store;
|
||||
}
|
||||
/**
|
||||
* Simulates transferFrom call performed by a proxy
|
||||
@@ -91,7 +89,7 @@ export class ExchangeTransferSimulator {
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ import { ExchangeContractErrs, Order, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||
import { ExchangeContract } from '../contract_wrappers/generated/exchange';
|
||||
import { TradeSide, TransferType } from '../types';
|
||||
import { constants } from '../utils/constants';
|
||||
import { utils } from '../utils/utils';
|
||||
@@ -11,7 +11,7 @@ import { utils } from '../utils/utils';
|
||||
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||
|
||||
export class OrderValidationUtils {
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
private _exchangeContract: ExchangeContract;
|
||||
public static validateCancelOrderThrowIfInvalid(
|
||||
order: Order,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
@@ -104,8 +104,8 @@ export class OrderValidationUtils {
|
||||
.round(0);
|
||||
return fillMakerTokenAmount;
|
||||
}
|
||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
constructor(exchangeContract: ExchangeContract) {
|
||||
this._exchangeContract = exchangeContract;
|
||||
}
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
@@ -114,7 +114,9 @@ export class OrderValidationUtils {
|
||||
expectedFillTakerTokenAmount?: BigNumber,
|
||||
): Promise<void> {
|
||||
const orderHash = getOrderHashHex(signedOrder);
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash,
|
||||
);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
@@ -146,7 +148,9 @@ export class OrderValidationUtils {
|
||||
if (!isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
||||
throw new Error(OrderError.InvalidSignature);
|
||||
}
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash,
|
||||
);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
@@ -167,7 +171,7 @@ export class OrderValidationUtils {
|
||||
zrxTokenAddress,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||
const wouldRoundingErrorOccur = await this._exchangeContract.isRoundingError.callAsync(
|
||||
filledTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
|
@@ -5,6 +5,7 @@ import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ContractWrappers, ExchangeContractErrs } from '../src';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||
|
||||
@@ -44,7 +45,11 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
describe('#transferFromAsync', () => {
|
||||
beforeEach(() => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
contractWrappers.token,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
});
|
||||
it("throws if the user doesn't have enough allowance", async () => {
|
||||
return expect(
|
||||
|
@@ -6,7 +6,7 @@ import { provider } from './utils/web3_wrapper';
|
||||
before('migrate contracts', async function(): Promise<void> {
|
||||
// HACK: Since the migrations take longer then our global mocha timeout limit
|
||||
// we manually increase it for this before hook.
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
const mochaTestTimeoutMs = 50000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
|
@@ -8,6 +8,7 @@ import 'make-promises-safe';
|
||||
import * as Sinon from 'sinon';
|
||||
|
||||
import { ContractWrappers, ExchangeContractErrs, SignedOrder, Token } from '../src';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||
import { OrderValidationUtils } from '../src/utils/order_validation_utils';
|
||||
@@ -332,7 +333,11 @@ describe('OrderValidation', () => {
|
||||
return Sinon.match((value: BigNumber) => value.eq(expected));
|
||||
};
|
||||
beforeEach('create exchangeTransferSimulator', async () => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
contractWrappers.token,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
transferFromAsync = Sinon.spy();
|
||||
exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
|
||||
});
|
||||
|
@@ -21,6 +21,7 @@
|
||||
"contracts": [
|
||||
"AssetProxyOwner",
|
||||
"DummyERC20Token",
|
||||
"DummyERC721Receiver",
|
||||
"DummyERC721Token",
|
||||
"ERC20Proxy",
|
||||
"ERC721Proxy",
|
||||
@@ -28,8 +29,10 @@
|
||||
"MixinAuthorizable",
|
||||
"MultiSigWallet",
|
||||
"MultiSigWalletWithTimeLock",
|
||||
"TestAssetDataDecoders",
|
||||
"TestAssetProxyDispatcher",
|
||||
"TestLibBytes",
|
||||
"TestLibMem",
|
||||
"TestLibs",
|
||||
"TestSignatureValidator",
|
||||
"TokenRegistry",
|
||||
|
@@ -18,19 +18,21 @@
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"run_mocha": "mocha --require source-map-support/register 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"clean": "shx rm -rf lib src/generated_contract_wrappers",
|
||||
"generate_contract_wrappers":
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetDataDecoders|TestAssetProxyDispatcher|TestLibBytes|TestLibMem|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -34,34 +34,30 @@ contract ERC20Proxy is
|
||||
uint8 constant PROXY_ID = 1;
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
uint256 length = assetMetadata.length;
|
||||
// Decode asset data.
|
||||
(
|
||||
uint8 proxyId,
|
||||
address token
|
||||
) = decodeERC20AssetData(assetData);
|
||||
|
||||
// Data must be intended for this proxy.
|
||||
require(
|
||||
length == 21,
|
||||
LENGTH_21_REQUIRED
|
||||
);
|
||||
// TODO: Is this too inflexible in the future?
|
||||
require(
|
||||
uint8(assetMetadata[length - 1]) == PROXY_ID,
|
||||
proxyId == PROXY_ID,
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// Decode metadata.
|
||||
address token = readAddress(assetMetadata, 0);
|
||||
|
||||
// Transfer tokens.
|
||||
bool success = IERC20Token(token).transferFrom(from, to, amount);
|
||||
require(
|
||||
@@ -79,4 +75,30 @@ contract ERC20Proxy is
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC20 proxy id.
|
||||
/// @return token ERC20 token address.
|
||||
function decodeERC20AssetData(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token
|
||||
)
|
||||
{
|
||||
// Validate encoded data length
|
||||
uint256 length = assetData.length;
|
||||
require(
|
||||
length == 21,
|
||||
LENGTH_21_REQUIRED
|
||||
);
|
||||
|
||||
// Decode data
|
||||
token = readAddress(assetData, 0);
|
||||
proxyId = uint8(assetData[length - 1]);
|
||||
|
||||
return (proxyId, token);
|
||||
}
|
||||
}
|
||||
|
@@ -34,29 +34,30 @@ contract ERC721Proxy is
|
||||
uint8 constant PROXY_ID = 2;
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Decode asset data.
|
||||
(
|
||||
uint8 proxyId,
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
|
||||
// Data must be intended for this proxy.
|
||||
uint256 length = assetMetadata.length;
|
||||
|
||||
require(
|
||||
length == 53,
|
||||
LENGTH_53_REQUIRED
|
||||
);
|
||||
|
||||
// TODO: Is this too inflexible in the future?
|
||||
require(
|
||||
uint8(assetMetadata[length - 1]) == PROXY_ID,
|
||||
proxyId == PROXY_ID,
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
@@ -66,15 +67,13 @@ contract ERC721Proxy is
|
||||
INVALID_AMOUNT
|
||||
);
|
||||
|
||||
// Decode metadata
|
||||
address token = readAddress(assetMetadata, 0);
|
||||
uint256 tokenId = readUint256(assetMetadata, 20);
|
||||
|
||||
// Transfer token.
|
||||
// Either succeeds or throws.
|
||||
// @TODO: Call safeTransferFrom if there is additional
|
||||
// data stored in `assetMetadata`.
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
// Transfer token. Saves gas by calling safeTransferFrom only
|
||||
// when there is receiverData present. Either succeeds or throws.
|
||||
if(receiverData.length > 0) {
|
||||
ERC721Token(token).safeTransferFrom(from, to, tokenId, receiverData);
|
||||
} else {
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
@@ -86,4 +85,44 @@ contract ERC721Proxy is
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function decodeERC721AssetData(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
// Validate encoded data length
|
||||
uint256 length = assetData.length;
|
||||
require(
|
||||
length >= 53,
|
||||
LENGTH_AT_LEAST_53_REQUIRED
|
||||
);
|
||||
|
||||
// Decode asset data.
|
||||
token = readAddress(assetData, 0);
|
||||
tokenId = readUint256(assetData, 20);
|
||||
if (length > 53) {
|
||||
receiverData = readBytes(assetData, 52);
|
||||
}
|
||||
proxyId = uint8(assetData[length - 1]);
|
||||
|
||||
return (
|
||||
proxyId,
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -28,12 +28,12 @@ contract MixinAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -42,7 +42,7 @@ contract MixinAssetProxy is
|
||||
onlyAuthorized
|
||||
{
|
||||
transferFromInternal(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
@@ -50,12 +50,12 @@ contract MixinAssetProxy is
|
||||
}
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param assetData Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetMetadata,
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
@@ -63,9 +63,9 @@ contract MixinAssetProxy is
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
for (uint256 i = 0; i < assetMetadata.length; i++) {
|
||||
for (uint256 i = 0; i < assetData.length; i++) {
|
||||
transferFromInternal(
|
||||
assetMetadata[i],
|
||||
assetData[i],
|
||||
from[i],
|
||||
to[i],
|
||||
amounts[i]
|
||||
|
@@ -26,12 +26,12 @@ contract IAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -39,12 +39,12 @@ contract IAssetProxy is
|
||||
external;
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param assetData Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetMetadata,
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
|
@@ -29,9 +29,9 @@ contract LibAssetProxyErrors {
|
||||
/// AssetProxy errors ///
|
||||
string constant ASSET_PROXY_ID_MISMATCH = "ASSET_PROXY_ID_MISMATCH"; // Proxy id in metadata does not match this proxy id.
|
||||
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
|
||||
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
|
||||
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
|
||||
|
||||
/// Length validation errors ///
|
||||
string constant LENGTH_21_REQUIRED = "LENGTH_21_REQUIRED"; // Byte array must have a length of 21.
|
||||
string constant LENGTH_53_REQUIRED = "LENGTH_53_REQUIRED"; // Byte array must have a length of 53.
|
||||
string constant LENGTH_AT_LEAST_53_REQUIRED = "LENGTH_AT_LEAST_53_REQUIRED"; // Byte array must have a length of at least 53.
|
||||
}
|
||||
|
@@ -26,12 +26,12 @@ contract MAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
|
@@ -40,11 +40,11 @@ contract Exchange is
|
||||
string constant public VERSION = "2.0.1-alpha";
|
||||
|
||||
// Mixins are instantiated in the order they are inherited
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
MixinExchangeCore()
|
||||
MixinMatchOrders()
|
||||
MixinSettlement(_zrxProxyData)
|
||||
MixinSettlement(_zrxAssetData)
|
||||
MixinSignatureValidator()
|
||||
MixinTransactions()
|
||||
MixinAssetProxyDispatcher()
|
||||
|
@@ -80,12 +80,12 @@ contract MixinAssetProxyDispatcher is
|
||||
}
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -96,16 +96,16 @@ contract MixinAssetProxyDispatcher is
|
||||
if (amount > 0) {
|
||||
|
||||
// Lookup asset proxy
|
||||
uint256 length = assetMetadata.length;
|
||||
uint256 length = assetData.length;
|
||||
require(
|
||||
length > 0,
|
||||
LENGTH_GREATER_THAN_0_REQUIRED
|
||||
);
|
||||
uint8 assetProxyId = uint8(assetMetadata[length - 1]);
|
||||
uint8 assetProxyId = uint8(assetData[length - 1]);
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetMetadata, from, to, amount);
|
||||
assetProxy.transferFrom(assetData, from, to, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ contract MixinSettlement is
|
||||
bytes internal ZRX_PROXY_DATA;
|
||||
|
||||
/// @dev Gets the ZRX metadata used for fee transfers.
|
||||
function zrxProxyData()
|
||||
function zrxAssetData()
|
||||
external
|
||||
view
|
||||
returns (bytes memory)
|
||||
@@ -48,13 +48,13 @@ contract MixinSettlement is
|
||||
return ZRX_PROXY_DATA;
|
||||
}
|
||||
|
||||
/// TODO: _zrxProxyData should be a constant in production.
|
||||
/// TODO: _zrxAssetData should be a constant in production.
|
||||
/// @dev Constructor sets the metadata that will be used for paying ZRX fees.
|
||||
/// @param _zrxProxyData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
/// @param _zrxAssetData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
{
|
||||
ZRX_PROXY_DATA = _zrxProxyData;
|
||||
ZRX_PROXY_DATA = _zrxAssetData;
|
||||
}
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
|
@@ -40,7 +40,8 @@ contract MixinWrapperFunctions is
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
@@ -65,7 +66,8 @@ contract MixinWrapperFunctions is
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
@@ -91,12 +93,12 @@ contract MixinWrapperFunctions is
|
||||
// | | 0x0E0 | | 8. takerFeeAmount |
|
||||
// | | 0x100 | | 9. expirationTimeSeconds |
|
||||
// | | 0x120 | | 10. salt |
|
||||
// | | 0x140 | | 11. Offset to makerAssetProxyMetadata (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetProxyMetadata (*) |
|
||||
// | | 0x180 | 32 | makerAssetProxyMetadata Length |
|
||||
// | | 0x1A0 | ** | makerAssetProxyMetadata Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetProxyMetadata Length |
|
||||
// | | 0x1E0 | ** | takerAssetProxyMetadata Contents |
|
||||
// | | 0x140 | | 11. Offset to makerAssetData (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetData (*) |
|
||||
// | | 0x180 | 32 | makerAssetData Length |
|
||||
// | | 0x1A0 | ** | makerAssetData Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetData Length |
|
||||
// | | 0x1E0 | ** | takerAssetData Contents |
|
||||
// | | 0x200 | 32 | signature Length |
|
||||
// | | 0x220 | ** | signature Contents |
|
||||
|
||||
@@ -163,43 +165,43 @@ contract MixinWrapperFunctions is
|
||||
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
|
||||
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
|
||||
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetProxyMetadata
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetProxyMetadata
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
|
||||
dataAreaEnd := add(dataAreaEnd, 0x180)
|
||||
sourceOffset := add(sourceOffset, 0x180)
|
||||
|
||||
// Write offset to <order.makerAssetProxyMetadata>
|
||||
// Write offset to <order.makerAssetData>
|
||||
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.makerAssetProxyMetadata>
|
||||
// Calculate length of <order.makerAssetData>
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.makerAssetProxyMetadata>
|
||||
// Write length of <order.makerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.makerAssetProxyMetadata>
|
||||
// Write contents of <order.makerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Write offset to <order.takerAssetProxyMetadata>
|
||||
// Write offset to <order.takerAssetData>
|
||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.takerAssetProxyMetadata>
|
||||
// Calculate length of <order.takerAssetData>
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.takerAssetProxyMetadata>
|
||||
// Write length of <order.takerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.takerAssetProxyMetadata>
|
||||
// Write contents of <order.takerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
@@ -264,7 +266,8 @@ contract MixinWrapperFunctions is
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
@@ -283,7 +286,8 @@ contract MixinWrapperFunctions is
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
@@ -303,7 +307,8 @@ contract MixinWrapperFunctions is
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
@@ -323,7 +328,8 @@ contract MixinWrapperFunctions is
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
@@ -366,7 +372,8 @@ contract MixinWrapperFunctions is
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
@@ -408,7 +415,8 @@ contract MixinWrapperFunctions is
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
@@ -459,7 +467,8 @@ contract MixinWrapperFunctions is
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
|
@@ -28,7 +28,8 @@ contract IAssetProxyDispatcher {
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy)
|
||||
address oldAssetProxy
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
|
@@ -28,6 +28,7 @@ contract ITransactions {
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature)
|
||||
bytes signature
|
||||
)
|
||||
external;
|
||||
}
|
||||
|
@@ -33,7 +33,8 @@ contract IWrapperFunctions is
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
@@ -46,7 +47,8 @@ contract IWrapperFunctions is
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
@@ -57,7 +59,8 @@ contract IWrapperFunctions is
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrKill.
|
||||
@@ -67,7 +70,8 @@ contract IWrapperFunctions is
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
@@ -78,7 +82,8 @@ contract IWrapperFunctions is
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
@@ -89,7 +94,8 @@ contract IWrapperFunctions is
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -102,7 +108,8 @@ contract IWrapperFunctions is
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -114,7 +121,8 @@ contract IWrapperFunctions is
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -127,7 +135,8 @@ contract IWrapperFunctions is
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
|
@@ -33,12 +33,12 @@ contract MAssetProxyDispatcher is
|
||||
);
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
|
@@ -31,7 +31,8 @@ contract DummyERC20Token is Mintable, Ownable {
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint256 _decimals,
|
||||
uint256 _totalSupply)
|
||||
uint256 _totalSupply
|
||||
)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Smart Contract Solutions, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../../tokens/ERC721Token/IERC721Receiver.sol";
|
||||
|
||||
contract DummyERC721Receiver is
|
||||
IERC721Receiver
|
||||
{
|
||||
|
||||
event TokenReceived(
|
||||
address from,
|
||||
uint256 tokenId,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/**
|
||||
* @notice Handle the receipt of an NFT
|
||||
* @dev The ERC721 smart contract calls this function on the recipient
|
||||
* after a `safetransfer`. This function MAY throw to revert and reject the
|
||||
* transfer. This function MUST use 50,000 gas or less. Return of other
|
||||
* than the magic value MUST result in the transaction being reverted.
|
||||
* Note: the contract address is always the message sender.
|
||||
* @param _from The sending address
|
||||
* @param _tokenId The NFT identifier which is being transfered
|
||||
* @param _data Additional data with no specified format
|
||||
* @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
|
||||
*/
|
||||
function onERC721Received(
|
||||
address _from,
|
||||
uint256 _tokenId,
|
||||
bytes _data
|
||||
)
|
||||
public
|
||||
returns (bytes4)
|
||||
{
|
||||
emit TokenReceived(_from, _tokenId, _data);
|
||||
return ERC721_RECEIVED;
|
||||
}
|
||||
}
|
@@ -34,7 +34,8 @@ contract DummyERC721Token is
|
||||
*/
|
||||
constructor (
|
||||
string name,
|
||||
string symbol)
|
||||
string symbol
|
||||
)
|
||||
public
|
||||
ERC721Token(name, symbol)
|
||||
{}
|
||||
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../protocol/AssetProxy/ERC20Proxy.sol";
|
||||
import "../../protocol/AssetProxy/ERC721Proxy.sol";
|
||||
|
||||
contract TestAssetDataDecoders is
|
||||
ERC20Proxy,
|
||||
ERC721Proxy
|
||||
{
|
||||
|
||||
/// @dev Decodes ERC20 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC20 proxy id.
|
||||
/// @return token ERC20 token address.
|
||||
function publicDecodeERC20Data(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token
|
||||
)
|
||||
{
|
||||
(proxyId, token) = decodeERC20AssetData(assetData);
|
||||
return (proxyId, token);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function publicDecodeERC721Data(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
(
|
||||
proxyId,
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
return (
|
||||
proxyId,
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
@@ -23,12 +23,12 @@ import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
|
||||
|
||||
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
|
||||
function publicDispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
{
|
||||
dispatchTransferFrom(assetMetadata, from, to, amount);
|
||||
dispatchTransferFrom(assetData, from, to, amount);
|
||||
}
|
||||
}
|
||||
|
@@ -68,7 +68,8 @@ contract TestLibBytes is
|
||||
/// @return address from byte array.
|
||||
function publicReadAddress(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (address result)
|
||||
@@ -84,7 +85,8 @@ contract TestLibBytes is
|
||||
function publicWriteAddress(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
address input)
|
||||
address input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -99,7 +101,8 @@ contract TestLibBytes is
|
||||
/// @return bytes32 value from byte array.
|
||||
function publicReadBytes32(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
@@ -115,7 +118,8 @@ contract TestLibBytes is
|
||||
function publicWriteBytes32(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes32 input)
|
||||
bytes32 input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -130,7 +134,8 @@ contract TestLibBytes is
|
||||
/// @return uint256 value from byte array.
|
||||
function publicReadUint256(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 result)
|
||||
@@ -146,7 +151,8 @@ contract TestLibBytes is
|
||||
function publicWriteUint256(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
uint256 input)
|
||||
uint256 input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -166,4 +172,38 @@ contract TestLibBytes is
|
||||
result = readFirst4(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Reads nested bytes from a specific position.
|
||||
/// @param b Byte array containing nested bytes.
|
||||
/// @param index Index of nested bytes.
|
||||
/// @return result Nested bytes.
|
||||
function publicReadBytes(
|
||||
bytes memory b,
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory result)
|
||||
{
|
||||
result = readBytes(b, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Inserts bytes at a specific position in a byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
/// @param input bytes to insert.
|
||||
/// @return b Updated input byte array
|
||||
function publicWriteBytes(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes memory input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
writeBytes(b, index, input);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../../utils/LibMem/LibMem.sol";
|
||||
|
||||
contract TestLibMem is
|
||||
LibMem
|
||||
{
|
||||
|
||||
/// @dev Copies a block of memory from one location to another.
|
||||
/// @param mem Memory contents we want to apply memCopy to
|
||||
/// @param dest Destination offset into <mem>.
|
||||
/// @param source Source offset into <mem>.
|
||||
/// @param length Length of bytes to copy from <source> to <dest>
|
||||
/// @return mem Memory contents after calling memCopy.
|
||||
function testMemcpy(
|
||||
bytes mem,
|
||||
uint256 dest,
|
||||
uint256 source,
|
||||
uint256 length
|
||||
)
|
||||
public // not external, we need input in memory
|
||||
pure
|
||||
returns (bytes)
|
||||
{
|
||||
// Sanity check. Overflows are not checked.
|
||||
require(source + length <= mem.length);
|
||||
require(dest + length <= mem.length);
|
||||
|
||||
// Get pointer to memory contents
|
||||
uint256 offset = getMemAddress(mem) + 32;
|
||||
|
||||
// Execute memCopy adjusted for memory array location
|
||||
memCopy(offset + dest, offset + source, length);
|
||||
|
||||
// Return modified memory contents
|
||||
return mem;
|
||||
}
|
||||
}
|
@@ -18,14 +18,18 @@
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract LibBytes {
|
||||
import "../LibMem/LibMem.sol";
|
||||
|
||||
contract LibBytes is
|
||||
LibMem
|
||||
{
|
||||
|
||||
// Revert reasons
|
||||
string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
|
||||
string constant GTE_4_LENGTH_REQUIRED = "Length must be greater than or equal to 4.";
|
||||
string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
|
||||
string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
|
||||
string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
|
||||
string constant GREATER_THAN_ZERO_LENGTH_REQUIRED = "GREATER_THAN_ZERO_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED";
|
||||
|
||||
/// @dev Pops the last byte off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
@@ -37,12 +41,12 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length > 0,
|
||||
GT_ZERO_LENGTH_REQUIRED
|
||||
GREATER_THAN_ZERO_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Store last byte.
|
||||
result = b[b.length - 1];
|
||||
|
||||
|
||||
assembly {
|
||||
// Decrement length of byte array.
|
||||
let newLen := sub(mload(b), 1)
|
||||
@@ -61,7 +65,7 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= 20,
|
||||
GTE_20_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Store last 20 bytes.
|
||||
@@ -124,8 +128,8 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 20, // 20 is length of address
|
||||
GTE_20_LENGTH_REQUIRED
|
||||
);
|
||||
GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Add offset to index:
|
||||
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
|
||||
@@ -156,8 +160,8 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 20, // 20 is length of address
|
||||
GTE_20_LENGTH_REQUIRED
|
||||
);
|
||||
GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Add offset to index:
|
||||
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
|
||||
@@ -195,7 +199,7 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 32,
|
||||
GTE_32_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
@@ -222,7 +226,7 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 32,
|
||||
GTE_32_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
@@ -274,11 +278,72 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= 4,
|
||||
GTE_4_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED
|
||||
);
|
||||
assembly {
|
||||
result := mload(add(b, 32))
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Reads nested bytes from a specific position.
|
||||
/// @param b Byte array containing nested bytes.
|
||||
/// @param index Index of nested bytes.
|
||||
/// @return result Nested bytes.
|
||||
function readBytes(
|
||||
bytes memory b,
|
||||
uint256 index
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory result)
|
||||
{
|
||||
// Read length of nested bytes
|
||||
uint256 nestedBytesLength = readUint256(b, index);
|
||||
index += 32;
|
||||
|
||||
// Assert length of <b> is valid, given
|
||||
// length of nested bytes
|
||||
require(
|
||||
b.length >= index + nestedBytesLength,
|
||||
GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Allocate memory and copy value to result
|
||||
result = new bytes(nestedBytesLength);
|
||||
memCopy(
|
||||
getMemAddress(result) + 32, // +32 skips array length
|
||||
getMemAddress(b) + index + 32,
|
||||
nestedBytesLength
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Inserts bytes at a specific position in a byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
/// @param input bytes to insert.
|
||||
function writeBytes(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes memory input
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
// Assert length of <b> is valid, given
|
||||
// length of input
|
||||
require(
|
||||
b.length >= index + 32 /* 32 bytes to store length */ + input.length,
|
||||
GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Copy <input> into <b>
|
||||
memCopy(
|
||||
getMemAddress(b) + 32 + index, // +32 to skip length of <b>
|
||||
getMemAddress(input), // includes length of <input>
|
||||
input.length + 32 // +32 bytes to store <input> length
|
||||
);
|
||||
}
|
||||
}
|
||||
|
140
packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol
Normal file
140
packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract LibMem
|
||||
{
|
||||
|
||||
/// @dev Gets the memory address for a byte array.
|
||||
/// @param input Byte array to lookup.
|
||||
/// @return memoryAddress Memory address of byte array.
|
||||
function getMemAddress(bytes memory input)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 memoryAddress)
|
||||
{
|
||||
assembly {
|
||||
memoryAddress := input
|
||||
}
|
||||
return memoryAddress;
|
||||
}
|
||||
|
||||
/// @dev Copies `length` bytes from memory location `source` to `dest`.
|
||||
/// @param dest memory address to copy bytes to.
|
||||
/// @param source memory address to copy bytes from.
|
||||
/// @param length number of bytes to copy.
|
||||
function memCopy(
|
||||
uint256 dest,
|
||||
uint256 source,
|
||||
uint256 length
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
if (length < 32) {
|
||||
// Handle a partial word by reading destination and masking
|
||||
// off the bits we are interested in.
|
||||
// This correctly handles overlap, zero lengths and source == dest
|
||||
assembly {
|
||||
let mask := sub(exp(256, sub(32, length)), 1)
|
||||
let s := and(mload(source), not(mask))
|
||||
let d := and(mload(dest), mask)
|
||||
mstore(dest, or(s, d))
|
||||
}
|
||||
} else {
|
||||
// Skip the O(length) loop when source == dest.
|
||||
if (source == dest) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For large copies we copy whole words at a time. The final
|
||||
// word is aligned to the end of the range (instead of after the
|
||||
// previous) to handle partial words. So a copy will look like this:
|
||||
//
|
||||
// ####
|
||||
// ####
|
||||
// ####
|
||||
// ####
|
||||
//
|
||||
// We handle overlap in the source and destination range by
|
||||
// changing the copying direction. This prevents us from
|
||||
// overwriting parts of source that we still need to copy.
|
||||
//
|
||||
// This correctly handles source == dest
|
||||
//
|
||||
if (source > dest) {
|
||||
assembly {
|
||||
// Record the total number of full words to copy
|
||||
let nWords := div(length, 32)
|
||||
|
||||
// We subtract 32 from `sEnd` and `dEnd` because it
|
||||
// is easier to compare with in the loop, and these
|
||||
// are also the addresses we need for copying the
|
||||
// last bytes.
|
||||
length := sub(length, 32)
|
||||
let sEnd := add(source, length)
|
||||
let dEnd := add(dest, length)
|
||||
|
||||
// Remember the last 32 bytes of source
|
||||
// This needs to be done here and not after the loop
|
||||
// because we may have overwritten the last bytes in
|
||||
// source already due to overlap.
|
||||
let last := mload(sEnd)
|
||||
|
||||
// Copy whole words front to back
|
||||
for {let i := 0} lt(i, nWords) {i := add(i, 1)} {
|
||||
mstore(dest, mload(source))
|
||||
source := add(source, 32)
|
||||
dest := add(dest, 32)
|
||||
}
|
||||
|
||||
// Write the last 32 bytes
|
||||
mstore(dEnd, last)
|
||||
}
|
||||
} else {
|
||||
assembly {
|
||||
// Record the total number of full words to copy
|
||||
let nWords := div(length, 32)
|
||||
|
||||
// We subtract 32 from `sEnd` and `dEnd` because those
|
||||
// are the starting points when copying a word at the end.
|
||||
length := sub(length, 32)
|
||||
let sEnd := add(source, length)
|
||||
let dEnd := add(dest, length)
|
||||
|
||||
// Remember the first 32 bytes of source
|
||||
// This needs to be done here and not after the loop
|
||||
// because we may have overwritten the first bytes in
|
||||
// source already due to overlap.
|
||||
let first := mload(source)
|
||||
|
||||
// Copy whole words back to front
|
||||
for {let i := 0} lt(i, nWords) {i := add(i, 1)} {
|
||||
mstore(dEnd, mload(sEnd))
|
||||
sEnd := sub(sEnd, 32)
|
||||
dEnd := sub(dEnd, 32)
|
||||
}
|
||||
|
||||
// Write the first 32 bytes
|
||||
mstore(dest, first)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
|
||||
import * as AssetProxyOwner from '../artifacts/AssetProxyOwner.json';
|
||||
import * as DummyERC20Token from '../artifacts/DummyERC20Token.json';
|
||||
import * as DummyERC721Receiver from '../artifacts/DummyERC721Receiver.json';
|
||||
import * as DummyERC721Token from '../artifacts/DummyERC721Token.json';
|
||||
import * as ERC20Proxy from '../artifacts/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../artifacts/ERC721Proxy.json';
|
||||
@@ -9,8 +10,10 @@ import * as Exchange from '../artifacts/Exchange.json';
|
||||
import * as MixinAuthorizable from '../artifacts/MixinAuthorizable.json';
|
||||
import * as MultiSigWallet from '../artifacts/MultiSigWallet.json';
|
||||
import * as MultiSigWalletWithTimeLock from '../artifacts/MultiSigWalletWithTimeLock.json';
|
||||
import * as TestAssetDataDecoders from '../artifacts/TestAssetDataDecoders.json';
|
||||
import * as TestAssetProxyDispatcher from '../artifacts/TestAssetProxyDispatcher.json';
|
||||
import * as TestLibBytes from '../artifacts/TestLibBytes.json';
|
||||
import * as TestLibMem from '../artifacts/TestLibMem.json';
|
||||
import * as TestLibs from '../artifacts/TestLibs.json';
|
||||
import * as TestSignatureValidator from '../artifacts/TestSignatureValidator.json';
|
||||
import * as TokenRegistry from '../artifacts/TokenRegistry.json';
|
||||
@@ -21,6 +24,7 @@ import * as ZRX from '../artifacts/ZRXToken.json';
|
||||
export const artifacts = {
|
||||
AssetProxyOwner: (AssetProxyOwner as any) as ContractArtifact,
|
||||
DummyERC20Token: (DummyERC20Token as any) as ContractArtifact,
|
||||
DummyERC721Receiver: (DummyERC721Receiver as any) as ContractArtifact,
|
||||
DummyERC721Token: (DummyERC721Token as any) as ContractArtifact,
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
|
||||
@@ -30,7 +34,9 @@ export const artifacts = {
|
||||
MultiSigWallet: (MultiSigWallet as any) as ContractArtifact,
|
||||
MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
|
||||
TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
|
||||
TestAssetDataDecoders: (TestAssetDataDecoders as any) as ContractArtifact,
|
||||
TestLibBytes: (TestLibBytes as any) as ContractArtifact,
|
||||
TestLibMem: (TestLibMem as any) as ContractArtifact,
|
||||
TestLibs: (TestLibs as any) as ContractArtifact,
|
||||
TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
|
||||
TokenRegistry: (TokenRegistry as any) as ContractArtifact,
|
||||
|
@@ -19,11 +19,11 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [
|
||||
export const constants = {
|
||||
INVALID_OPCODE: 'invalid opcode',
|
||||
REVERT: 'revert',
|
||||
LIB_BYTES_GT_ZERO_LENGTH_REQUIRED: 'Length must be greater than 0.',
|
||||
LIB_BYTES_GTE_4_LENGTH_REQUIRED: 'Length must be greater than or equal to 4.',
|
||||
LIB_BYTES_GTE_20_LENGTH_REQUIRED: 'Length must be greater than or equal to 20.',
|
||||
LIB_BYTES_GTE_32_LENGTH_REQUIRED: 'Length must be greater than or equal to 32.',
|
||||
LIB_BYTES_INDEX_OUT_OF_BOUNDS: 'Specified array index is out of bounds.',
|
||||
LIB_BYTES_GREATER_THAN_ZERO_LENGTH_REQUIRED: 'GREATER_THAN_ZERO_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED',
|
||||
ERC20_INSUFFICIENT_BALANCE: 'Insufficient balance to complete transfer.',
|
||||
ERC20_INSUFFICIENT_ALLOWANCE: 'Insufficient allowance to complete transfer.',
|
||||
TESTRPC_NETWORK_ID: 50,
|
||||
|
@@ -14,7 +14,8 @@ export const coverage = {
|
||||
_getCoverageSubprovider(): CoverageSubprovider {
|
||||
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
|
||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
|
||||
const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress);
|
||||
const isVerbose = true;
|
||||
const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
|
||||
return subprovider;
|
||||
},
|
||||
};
|
||||
|
@@ -237,11 +237,11 @@ export class MatchOrderTester {
|
||||
const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner);
|
||||
const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner);
|
||||
// Left Maker Asset (Right Taker Asset)
|
||||
const makerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.makerAssetData);
|
||||
const makerAssetProxyIdLeft = assetProxyUtils.decodeAssetDataId(signedOrderLeft.makerAssetData);
|
||||
if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
// Decode asset data
|
||||
const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc20ProxyData.tokenAddress;
|
||||
const erc20AssetData = assetProxyUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc20AssetData.tokenAddress;
|
||||
const takerAssetAddressRight = makerAssetAddressLeft;
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
@@ -259,9 +259,9 @@ export class MatchOrderTester {
|
||||
][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker);
|
||||
} else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
// Decode asset data
|
||||
const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc721ProxyData.tokenAddress;
|
||||
const makerAssetIdLeft = erc721ProxyData.tokenId;
|
||||
const erc721AssetData = assetProxyUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc721AssetData.tokenAddress;
|
||||
const makerAssetIdLeft = erc721AssetData.tokenId;
|
||||
const takerAssetAddressRight = makerAssetAddressLeft;
|
||||
const takerAssetIdRight = makerAssetIdLeft;
|
||||
// Left Maker
|
||||
@@ -272,11 +272,11 @@ export class MatchOrderTester {
|
||||
}
|
||||
// Left Taker Asset (Right Maker Asset)
|
||||
// Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset.
|
||||
const takerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.takerAssetData);
|
||||
const takerAssetProxyIdLeft = assetProxyUtils.decodeAssetDataId(signedOrderLeft.takerAssetData);
|
||||
if (takerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
// Decode asset data
|
||||
const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.takerAssetData);
|
||||
const takerAssetAddressLeft = erc20ProxyData.tokenAddress;
|
||||
const erc20AssetData = assetProxyUtils.decodeERC20AssetData(signedOrderLeft.takerAssetData);
|
||||
const takerAssetAddressLeft = erc20AssetData.tokenAddress;
|
||||
const makerAssetAddressRight = takerAssetAddressLeft;
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
@@ -290,9 +290,9 @@ export class MatchOrderTester {
|
||||
);
|
||||
} else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
// Decode asset data
|
||||
const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(signedOrderRight.makerAssetData);
|
||||
const makerAssetAddressRight = erc721ProxyData.tokenAddress;
|
||||
const makerAssetIdRight = erc721ProxyData.tokenId;
|
||||
const erc721AssetData = assetProxyUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
|
||||
const makerAssetAddressRight = erc721AssetData.tokenAddress;
|
||||
const makerAssetIdRight = erc721AssetData.tokenId;
|
||||
const takerAssetAddressLeft = makerAssetAddressRight;
|
||||
const takerAssetIdLeft = makerAssetIdRight;
|
||||
// Right Maker
|
||||
|
27
packages/contracts/src/utils/profiler.ts
Normal file
27
packages/contracts/src/utils/profiler.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
let profilerSubprovider: ProfilerSubprovider;
|
||||
|
||||
export const profiler = {
|
||||
start(): void {
|
||||
profiler.getProfilerSubproviderSingleton().start();
|
||||
},
|
||||
stop(): void {
|
||||
profiler.getProfilerSubproviderSingleton().stop();
|
||||
},
|
||||
getProfilerSubproviderSingleton(): ProfilerSubprovider {
|
||||
if (_.isUndefined(profilerSubprovider)) {
|
||||
profilerSubprovider = profiler._getProfilerSubprovider();
|
||||
}
|
||||
return profilerSubprovider;
|
||||
},
|
||||
_getProfilerSubprovider(): ProfilerSubprovider {
|
||||
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
|
||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
|
||||
const isVerbose = true;
|
||||
const subprovider = new ProfilerSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
|
||||
return subprovider;
|
||||
},
|
||||
};
|
@@ -90,11 +90,14 @@ export enum ContractName {
|
||||
AccountLevels = 'AccountLevels',
|
||||
EtherDelta = 'EtherDelta',
|
||||
Arbitrage = 'Arbitrage',
|
||||
TestAssetDataDecoders = 'TestAssetDataDecoders',
|
||||
TestAssetProxyDispatcher = 'TestAssetProxyDispatcher',
|
||||
TestLibMem = 'TestLibMem',
|
||||
TestLibs = 'TestLibs',
|
||||
TestSignatureValidator = 'TestSignatureValidator',
|
||||
ERC20Proxy = 'ERC20Proxy',
|
||||
ERC721Proxy = 'ERC721Proxy',
|
||||
DummyERC721Receiver = 'DummyERC721Receiver',
|
||||
DummyERC721Token = 'DummyERC721Token',
|
||||
TestLibBytes = 'TestLibBytes',
|
||||
Authorizable = 'Authorizable',
|
||||
|
@@ -1,8 +1,10 @@
|
||||
import { devConstants, env, EnvVars, web3Factory } from '@0xproject/dev-utils';
|
||||
import { prependSubprovider } from '@0xproject/subproviders';
|
||||
import { logUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
import { coverage } from './coverage';
|
||||
import { profiler } from './profiler';
|
||||
|
||||
enum ProviderType {
|
||||
Ganache = 'ganache',
|
||||
@@ -45,9 +47,29 @@ const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs :
|
||||
|
||||
export const provider = web3Factory.getRpcProvider(providerConfigs);
|
||||
const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
|
||||
const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler);
|
||||
if (isCoverageEnabled && isProfilerEnabled) {
|
||||
throw new Error(
|
||||
`Unfortunately for now you can't enable both coverage and profiler at the same time. They both use coverage.json file and there is no way to configure that.`,
|
||||
);
|
||||
}
|
||||
if (isCoverageEnabled) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
prependSubprovider(provider, coverageSubprovider);
|
||||
}
|
||||
if (isProfilerEnabled) {
|
||||
if (testProvider === ProviderType.Ganache) {
|
||||
logUtils.warn(
|
||||
"Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
logUtils.log(
|
||||
"By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
|
||||
);
|
||||
profilerSubprovider.stop();
|
||||
prependSubprovider(provider, profilerSubprovider);
|
||||
}
|
||||
|
||||
export const web3Wrapper = new Web3Wrapper(provider);
|
||||
|
103
packages/contracts/test/asset_proxy/decoder.ts
Normal file
103
packages/contracts/test/asset_proxy/decoder.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import { TestAssetDataDecodersContract } from '../../src/generated_contract_wrappers/test_asset_data_decoders';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('TestAssetDataDecoders', () => {
|
||||
let testAssetProxyDecoder: TestAssetDataDecodersContract;
|
||||
let testAddress: string;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// Setup accounts & addresses
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
testAddress = accounts[0];
|
||||
// Deploy TestLibMem
|
||||
testAssetProxyDecoder = await TestAssetDataDecodersContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestAssetDataDecoders,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('Asset Data Decoders', () => {
|
||||
it('should correctly decode ERC20 asset data)', async () => {
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(testAddress);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC20AssetData(encodedAssetData);
|
||||
let decodedAssetProxyId: number;
|
||||
let decodedTokenAddress: string;
|
||||
[decodedAssetProxyId, decodedTokenAddress] = await testAssetProxyDecoder.publicDecodeERC20Data.callAsync(
|
||||
encodedAssetData,
|
||||
);
|
||||
expect(decodedAssetProxyId).to.be.equal(expectedDecodedAssetData.assetProxyId);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
});
|
||||
|
||||
it('should correctly decode ERC721 asset data', async () => {
|
||||
const tokenId = generatePseudoRandomSalt();
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
|
||||
let decodedAssetProxyId: number;
|
||||
let decodedTokenAddress: string;
|
||||
let decodedTokenId: BigNumber;
|
||||
let decodedData: string;
|
||||
[
|
||||
decodedAssetProxyId,
|
||||
decodedTokenAddress,
|
||||
decodedTokenId,
|
||||
decodedData,
|
||||
] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
|
||||
expect(decodedAssetProxyId).to.be.equal(expectedDecodedAssetData.assetProxyId);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
|
||||
expect(decodedData).to.be.equal(expectedDecodedAssetData.receiverData);
|
||||
});
|
||||
|
||||
it('should correctly decode ERC721 asset data with receiver data', async () => {
|
||||
const tokenId = generatePseudoRandomSalt();
|
||||
const receiverDataFirst32Bytes = ethUtil.bufferToHex(
|
||||
assetProxyUtils.encodeUint256(generatePseudoRandomSalt()),
|
||||
);
|
||||
const receiverDataExtraBytes = 'FFFF';
|
||||
// We add extra bytes to generate a value that doesn't fit perfectly into one word
|
||||
const receiverData = receiverDataFirst32Bytes + receiverDataExtraBytes;
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId, receiverData);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
|
||||
let decodedAssetProxyId: number;
|
||||
let decodedTokenAddress: string;
|
||||
let decodedTokenId: BigNumber;
|
||||
let decodedReceiverData: string;
|
||||
[
|
||||
decodedAssetProxyId,
|
||||
decodedTokenAddress,
|
||||
decodedTokenId,
|
||||
decodedReceiverData,
|
||||
] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
|
||||
expect(decodedAssetProxyId).to.be.equal(expectedDecodedAssetData.assetProxyId);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
|
||||
expect(decodedReceiverData).to.be.equal(expectedDecodedAssetData.receiverData);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,24 +1,33 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import {
|
||||
DummyERC721ReceiverContract,
|
||||
TokenReceivedContractEventArgs,
|
||||
} from '../../src/generated_contract_wrappers/dummy_e_r_c721_receiver';
|
||||
import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||
import { provider, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
import { LogDecoder } from '../../src/utils/log_decoder';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Asset Transfer Proxies', () => {
|
||||
let owner: string;
|
||||
let notAuthorized: string;
|
||||
@@ -28,6 +37,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let erc721Receiver: DummyERC721ReceiverContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc721Proxy: ERC721ProxyContract;
|
||||
|
||||
@@ -69,6 +79,11 @@ describe('Asset Transfer Proxies', () => {
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
|
||||
artifacts.DummyERC721Receiver,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -79,14 +94,14 @@ describe('Asset Transfer Proxies', () => {
|
||||
describe('Transfer Proxy - ERC20', () => {
|
||||
describe('transferFrom', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(10);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -105,14 +120,14 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should do nothing if transferring 0 amount of a token', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(0);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -131,8 +146,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if allowances are too low', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Create allowance less than transfer amount. Set allowance on proxy.
|
||||
const allowance = new BigNumber(0);
|
||||
const transferAmount = new BigNumber(10);
|
||||
@@ -145,7 +160,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
// Perform a transfer; expect this to fail.
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
transferAmount,
|
||||
@@ -155,20 +170,14 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if requesting address is not authorized', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(10);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{
|
||||
from: notAuthorized,
|
||||
},
|
||||
),
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(encodedAssetData, makerAddress, takerAddress, amount, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -177,16 +186,16 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should succesfully make multiple token transfers', async () => {
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const amount = new BigNumber(10);
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = _.times(numTransfers, () => encodedProxyMetadata);
|
||||
const assetData = _.times(numTransfers, () => encodedAssetData);
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => amount);
|
||||
|
||||
const txHash = await erc20Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
@@ -208,22 +217,18 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if not called by an authorized address', async () => {
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const amount = new BigNumber(10);
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = _.times(numTransfers, () => encodedProxyMetadata);
|
||||
const assetData = _.times(numTransfers, () => encodedAssetData);
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => amount);
|
||||
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
{ from: notAuthorized },
|
||||
),
|
||||
erc20Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -237,11 +242,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
describe('Transfer Proxy - ERC721', () => {
|
||||
describe('transferFrom', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
@@ -249,7 +251,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
const amount = new BigNumber(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -262,20 +264,102 @@ describe('Asset Transfer Proxies', () => {
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
});
|
||||
|
||||
it('should throw if transferring 0 amount of a token', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
it('should not call onERC721Received when transferring to a smart contract without receiver data', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
const txHash = await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
erc721Receiver.address,
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
||||
// Parse transaction logs
|
||||
const logDecoder = new LogDecoder(web3Wrapper, erc721Receiver.address);
|
||||
const tx = await logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
// Verify that no log was emitted by erc721 receiver
|
||||
expect(tx.logs.length).to.be.equal(0);
|
||||
// Verify transfer was successful
|
||||
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(erc721Receiver.address);
|
||||
});
|
||||
|
||||
it('should call onERC721Received when transferring to a smart contract with receiver data', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const receiverData = ethUtil.bufferToHex(assetProxyUtils.encodeUint256(generatePseudoRandomSalt()));
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
receiverData,
|
||||
);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
const txHash = await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
erc721Receiver.address,
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
||||
// Parse transaction logs
|
||||
const logDecoder = new LogDecoder(web3Wrapper, erc721Receiver.address);
|
||||
const tx = await logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
// Validate log emitted by erc721 receiver
|
||||
expect(tx.logs.length).to.be.equal(1);
|
||||
const tokenReceivedLog = tx.logs[0] as LogWithDecodedArgs<TokenReceivedContractEventArgs>;
|
||||
expect(tokenReceivedLog.args.from).to.be.equal(makerAddress);
|
||||
expect(tokenReceivedLog.args.tokenId).to.be.bignumber.equal(erc721MakerTokenId);
|
||||
expect(tokenReceivedLog.args.data).to.be.equal(receiverData);
|
||||
// Verify transfer was successful
|
||||
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(erc721Receiver.address);
|
||||
});
|
||||
|
||||
it('should throw if there is receiver data but contract does not have onERC721Received', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const receiverData = ethUtil.bufferToHex(assetProxyUtils.encodeUint256(generatePseudoRandomSalt()));
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
receiverData,
|
||||
);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
erc20Proxy.address, // the ERC20 proxy does not have an ERC721 receiver
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if transferring 0 amount of a token', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(0);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -285,11 +369,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if transferring > 1 amount of a token', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
@@ -297,7 +378,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
const amount = new BigNumber(500);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -307,11 +388,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if allowances are too low', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
// Remove transfer approval for makerAddress.
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, false, {
|
||||
@@ -322,29 +400,20 @@ describe('Asset Transfer Proxies', () => {
|
||||
// Perform a transfer; expect this to fail.
|
||||
const amount = new BigNumber(1);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{
|
||||
from: notAuthorized,
|
||||
},
|
||||
),
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(encodedAssetData, makerAddress, takerAddress, amount, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if requesting address is not authorized', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -360,16 +429,16 @@ describe('Asset Transfer Proxies', () => {
|
||||
const [makerTokenIdA, makerTokenIdB] = erc721TokensById[makerAddress][erc721Token.address];
|
||||
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = [
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdB),
|
||||
const assetData = [
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB),
|
||||
];
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => new BigNumber(1));
|
||||
|
||||
const txHash = await erc721Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
@@ -392,22 +461,18 @@ describe('Asset Transfer Proxies', () => {
|
||||
const [makerTokenIdA, makerTokenIdB] = erc721TokensById[makerAddress][erc721Token.address];
|
||||
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = [
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdB),
|
||||
const assetData = [
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB),
|
||||
];
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => new BigNumber(1));
|
||||
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
{ from: notAuthorized },
|
||||
),
|
||||
erc721Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -418,3 +483,4 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
|
@@ -87,7 +87,7 @@ describe('Exchange core', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -114,8 +114,8 @@ describe('Exchange core', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
@@ -711,8 +711,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -737,8 +737,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -759,8 +759,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -781,8 +781,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(2),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -803,8 +803,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(500),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -825,8 +825,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(0),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -846,8 +846,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -886,8 +886,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
|
||||
|
@@ -275,13 +275,13 @@ describe('AssetProxyDispatcher', () => {
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(10);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -301,12 +301,12 @@ describe('AssetProxyDispatcher', () => {
|
||||
|
||||
it('should throw if dispatching to unregistered proxy', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(10);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
|
@@ -38,8 +38,8 @@ describe('Exchange libs', () => {
|
||||
exchangeAddress: libs.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
|
@@ -96,7 +96,7 @@ describe('matchOrders', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -122,8 +122,8 @@ describe('matchOrders', () => {
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
exchangeAddress: exchange.address,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
};
|
||||
const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
|
||||
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParams);
|
||||
@@ -148,16 +148,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -182,16 +180,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -227,16 +223,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -261,16 +255,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -295,16 +287,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -334,8 +324,8 @@ describe('matchOrders', () => {
|
||||
// branch in the contract twice for this test.
|
||||
const signedOrderRight2 = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -364,8 +354,6 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
@@ -373,8 +361,8 @@ describe('matchOrders', () => {
|
||||
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -404,8 +392,6 @@ describe('matchOrders', () => {
|
||||
// branch in the contract twice for this test.
|
||||
const signedOrderLeft2 = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
@@ -437,16 +423,14 @@ describe('matchOrders', () => {
|
||||
const feeRecipientAddress = feeRecipientAddressLeft;
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress,
|
||||
@@ -465,16 +449,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -494,16 +476,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -523,16 +503,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -552,16 +530,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -581,16 +557,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: makerAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: makerAddressRight,
|
||||
@@ -609,16 +583,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -635,16 +607,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -661,16 +631,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -691,16 +659,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -721,16 +687,16 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -752,16 +718,16 @@ describe('matchOrders', () => {
|
||||
const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -787,16 +753,16 @@ describe('matchOrders', () => {
|
||||
const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
|
@@ -42,8 +42,8 @@ describe('MixinSignatureValidator', () => {
|
||||
exchangeAddress: signatureValidator.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
|
@@ -72,7 +72,7 @@ describe('Exchange transactions', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -91,8 +91,8 @@ describe('Exchange transactions', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerTokenAddress),
|
||||
};
|
||||
makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
@@ -216,6 +216,7 @@ describe('Exchange transactions', () => {
|
||||
await exchange.setSignatureValidatorApproval.sendTransactionAsync(whitelist.address, isApproved, {
|
||||
from: takerAddress,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
@@ -223,8 +224,8 @@ describe('Exchange transactions', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerTokenAddress),
|
||||
};
|
||||
whitelistOrderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
|
||||
});
|
||||
@@ -238,6 +239,7 @@ describe('Exchange transactions', () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
@@ -258,6 +260,7 @@ describe('Exchange transactions', () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
@@ -278,10 +281,12 @@ describe('Exchange transactions', () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
@@ -295,6 +300,7 @@ describe('Exchange transactions', () => {
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
|
@@ -81,7 +81,7 @@ describe('Exchange wrappers', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -108,8 +108,8 @@ describe('Exchange wrappers', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
@@ -304,7 +304,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: makerZRXBalance,
|
||||
makerFee: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -316,7 +316,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(makerZRXAllowance),
|
||||
makerFee: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -328,7 +328,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: takerZRXBalance,
|
||||
takerFee: new BigNumber(1),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -340,7 +340,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: new BigNumber(takerZRXAllowance),
|
||||
takerFee: new BigNumber(1),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -354,8 +354,8 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -692,7 +692,7 @@ describe('Exchange wrappers', () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
@@ -785,7 +785,7 @@ describe('Exchange wrappers', () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
@@ -874,7 +874,7 @@ describe('Exchange wrappers', () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
@@ -967,7 +967,7 @@ describe('Exchange wrappers', () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
|
@@ -1,10 +1,15 @@
|
||||
import { env, EnvVars } from '@0xproject/dev-utils';
|
||||
|
||||
import { coverage } from '../src/utils/coverage';
|
||||
import { profiler } from '../src/utils/profiler';
|
||||
|
||||
after('generate coverage report', async () => {
|
||||
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
await coverageSubprovider.writeCoverageAsync();
|
||||
}
|
||||
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
await profilerSubprovider.writeProfilerOutputAsync();
|
||||
}
|
||||
});
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import BN = require('bn.js');
|
||||
import * as chai from 'chai';
|
||||
@@ -28,6 +29,15 @@ describe('LibBytes', () => {
|
||||
let testAddress: string;
|
||||
const testBytes32 = '0x102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f01020';
|
||||
const testUint256 = new BigNumber(testBytes32, 16);
|
||||
let shortData: string;
|
||||
let shortTestBytes: string;
|
||||
let shortTestBytesAsBuffer: Buffer;
|
||||
let wordOfData: string;
|
||||
let wordOfTestBytes: string;
|
||||
let wordOfTestBytesAsBuffer: Buffer;
|
||||
let longData: string;
|
||||
let longTestBytes: string;
|
||||
let longTestBytesAsBuffer: Buffer;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -48,6 +58,26 @@ describe('LibBytes', () => {
|
||||
expect(byteArrayLongerThan32BytesLength).to.be.greaterThan(32);
|
||||
const testBytes32Length = ethUtil.toBuffer(testBytes32).byteLength;
|
||||
expect(testBytes32Length).to.be.equal(32);
|
||||
// Create short test bytes
|
||||
shortData = '0xffffaa';
|
||||
const encodedShortData = ethUtil.toBuffer(shortData);
|
||||
const shortDataLength = new BigNumber(encodedShortData.byteLength);
|
||||
const encodedShortDataLength = assetProxyUtils.encodeUint256(shortDataLength);
|
||||
shortTestBytesAsBuffer = Buffer.concat([encodedShortDataLength, encodedShortData]);
|
||||
shortTestBytes = ethUtil.bufferToHex(shortTestBytesAsBuffer);
|
||||
// Create test bytes one word in length
|
||||
wordOfData = ethUtil.bufferToHex(assetProxyUtils.encodeUint256(generatePseudoRandomSalt()));
|
||||
const encodedWordOfData = ethUtil.toBuffer(wordOfData);
|
||||
const wordOfDataLength = new BigNumber(encodedWordOfData.byteLength);
|
||||
const encodedWordOfDataLength = assetProxyUtils.encodeUint256(wordOfDataLength);
|
||||
wordOfTestBytesAsBuffer = Buffer.concat([encodedWordOfDataLength, encodedWordOfData]);
|
||||
wordOfTestBytes = ethUtil.bufferToHex(wordOfTestBytesAsBuffer);
|
||||
// Create long test bytes (combines short test bytes with word of test bytes)
|
||||
longData = ethUtil.bufferToHex(Buffer.concat([encodedShortData, encodedWordOfData]));
|
||||
const longDataLength = new BigNumber(encodedShortData.byteLength + encodedWordOfData.byteLength);
|
||||
const encodedLongDataLength = assetProxyUtils.encodeUint256(longDataLength);
|
||||
longTestBytesAsBuffer = Buffer.concat([encodedLongDataLength, encodedShortData, encodedWordOfData]);
|
||||
longTestBytes = ethUtil.bufferToHex(longTestBytesAsBuffer);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -60,7 +90,7 @@ describe('LibBytes', () => {
|
||||
it('should revert if length is 0', async () => {
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicPopByte.callAsync(constants.NULL_BYTES),
|
||||
constants.LIB_BYTES_GT_ZERO_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_THAN_ZERO_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -77,7 +107,7 @@ describe('LibBytes', () => {
|
||||
it('should revert if length is less than 20', async () => {
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicPopAddress.callAsync(byteArrayShorterThan20Bytes),
|
||||
constants.LIB_BYTES_GTE_20_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -163,7 +193,7 @@ describe('LibBytes', () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadAddress.callAsync(shortByteArray, offset),
|
||||
constants.LIB_BYTES_GTE_20_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -172,7 +202,7 @@ describe('LibBytes', () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadAddress.callAsync(byteArray, badOffset),
|
||||
constants.LIB_BYTES_GTE_20_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -209,7 +239,7 @@ describe('LibBytes', () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset),
|
||||
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -217,7 +247,7 @@ describe('LibBytes', () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes32.callAsync(testBytes32, badOffset),
|
||||
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -258,7 +288,7 @@ describe('LibBytes', () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset),
|
||||
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -269,7 +299,7 @@ describe('LibBytes', () => {
|
||||
const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadUint256.callAsync(byteArray, badOffset),
|
||||
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -291,7 +321,7 @@ describe('LibBytes', () => {
|
||||
const byteArrayLessThan4Bytes = '0x010101';
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadFirst4.callAsync(byteArrayLessThan4Bytes),
|
||||
constants.LIB_BYTES_GTE_4_LENGTH_REQUIRED,
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should return the first 4 bytes of a byte array of arbitrary length', async () => {
|
||||
@@ -300,4 +330,180 @@ describe('LibBytes', () => {
|
||||
expect(first4Bytes).to.equal(expectedFirst4Bytes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readBytes', () => {
|
||||
it('should successfully read short, nested array of bytes when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(shortTestBytes, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(shortData);
|
||||
});
|
||||
|
||||
it('should successfully read short, nested array of bytes when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, shortTestBytesAsBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(bytes).to.be.equal(shortData);
|
||||
});
|
||||
|
||||
it('should successfully read a nested array of bytes - one word in length - when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(wordOfTestBytes, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(wordOfData);
|
||||
});
|
||||
|
||||
it('should successfully read a nested array of bytes - one word in length - when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, wordOfTestBytesAsBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(bytes).to.be.equal(wordOfData);
|
||||
});
|
||||
|
||||
it('should successfully read long, nested array of bytes when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(longTestBytes, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(longData);
|
||||
});
|
||||
|
||||
it('should successfully read long, nested array of bytes when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, longTestBytesAsBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(bytes).to.be.equal(longData);
|
||||
});
|
||||
|
||||
it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
|
||||
// The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read.
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(byteArrayShorterThan32Bytes, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if we store a nested byte array length, without a nested byte array', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(testBytes32, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(byteArrayShorterThan32Bytes, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(testBytes32, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeBytes', () => {
|
||||
it('should successfully write short, nested array of bytes when it takes up the whole array)', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
|
||||
const bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, testBytesOffset, shortData);
|
||||
const bytesRead = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytesRead).to.be.equal(shortData);
|
||||
});
|
||||
|
||||
it('should successfully write short, nested array of bytes when it is offset in the array', async () => {
|
||||
// Write a prefix to the array
|
||||
const prefixData = '0xabcdef';
|
||||
const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
|
||||
const prefixOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(
|
||||
new Buffer(prefixDataAsBuffer.byteLength + shortTestBytesAsBuffer.byteLength),
|
||||
);
|
||||
let bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, prefixOffset, prefixData);
|
||||
// Write data after prefix
|
||||
const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
|
||||
bytesWritten = await libBytes.publicWriteBytes.callAsync(bytesWritten, testBytesOffset, shortData);
|
||||
// Read data after prefix and validate
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(shortData);
|
||||
});
|
||||
|
||||
it('should successfully write a nested array of bytes - one word in length - when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(wordOfTestBytesAsBuffer.byteLength));
|
||||
const bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, testBytesOffset, wordOfData);
|
||||
const bytesRead = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytesRead).to.be.equal(wordOfData);
|
||||
});
|
||||
|
||||
it('should successfully write a nested array of bytes - one word in length - when it is offset in the array', async () => {
|
||||
// Write a prefix to the array
|
||||
const prefixData = '0xabcdef';
|
||||
const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
|
||||
const prefixOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(
|
||||
new Buffer(prefixDataAsBuffer.byteLength + wordOfTestBytesAsBuffer.byteLength),
|
||||
);
|
||||
let bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, prefixOffset, prefixData);
|
||||
// Write data after prefix
|
||||
const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
|
||||
bytesWritten = await libBytes.publicWriteBytes.callAsync(bytesWritten, testBytesOffset, wordOfData);
|
||||
// Read data after prefix and validate
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(wordOfData);
|
||||
});
|
||||
|
||||
it('should successfully write a long, nested bytes when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(longTestBytesAsBuffer.byteLength));
|
||||
const bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, testBytesOffset, longData);
|
||||
const bytesRead = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytesRead).to.be.equal(longData);
|
||||
});
|
||||
|
||||
it('should successfully write long, nested array of bytes when it is offset in the array', async () => {
|
||||
// Write a prefix to the array
|
||||
const prefixData = '0xabcdef';
|
||||
const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
|
||||
const prefixOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(
|
||||
new Buffer(prefixDataAsBuffer.byteLength + longTestBytesAsBuffer.byteLength),
|
||||
);
|
||||
let bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, prefixOffset, prefixData);
|
||||
// Write data after prefix
|
||||
const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
|
||||
bytesWritten = await libBytes.publicWriteBytes.callAsync(bytesWritten, testBytesOffset, longData);
|
||||
// Read data after prefix and validate
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(longData);
|
||||
});
|
||||
|
||||
it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(1));
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteBytes.callAsync(emptyByteArray, offset, longData),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array)', async () => {
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteBytes.callAsync(emptyByteArray, badOffset, shortData),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable:max-file-line-count
|
||||
|
190
packages/contracts/test/libraries/lib_mem.ts
Normal file
190
packages/contracts/test/libraries/lib_mem.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { TestLibMemContract } from '../../src/generated_contract_wrappers/test_lib_mem';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { provider, txDefaults } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
// BUG: Ideally we would use Buffer.from(memory).toString('hex')
|
||||
// https://github.com/Microsoft/TypeScript/issues/23155
|
||||
const toHex = (buf: Uint8Array): string => buf.reduce((a, v) => a + ('00' + v.toString(16)).slice(-2), '0x');
|
||||
|
||||
const fromHex = (str: string): Uint8Array => Uint8Array.from(Buffer.from(str.slice(2), 'hex'));
|
||||
|
||||
describe('LibMem', () => {
|
||||
let testLibMem: TestLibMemContract;
|
||||
|
||||
before(async () => {
|
||||
// Deploy TestLibMem
|
||||
testLibMem = await TestLibMemContract.deployFrom0xArtifactAsync(artifacts.TestLibMem, provider, txDefaults);
|
||||
});
|
||||
|
||||
describe('memCopy', () => {
|
||||
// Create memory 0x000102...FF
|
||||
const memSize = 256;
|
||||
const memory = new Uint8Array(memSize).map((_, i) => i);
|
||||
const memHex = toHex(memory);
|
||||
|
||||
// Reference implementation to test against
|
||||
const refMemcpy = (_mem: Uint8Array, dest: number, source: number, length: number): Uint8Array =>
|
||||
Uint8Array.from(memory).copyWithin(dest, source, source + length);
|
||||
|
||||
// Test vectors: destination, source, length, job description
|
||||
type Tests = Array<[number, number, number, string]>;
|
||||
|
||||
const test = (tests: Tests) =>
|
||||
tests.forEach(([dest, source, length, job]) =>
|
||||
it(job, async () => {
|
||||
const expected = refMemcpy(memory, dest, source, length);
|
||||
const resultStr = await testLibMem.testMemcpy.callAsync(
|
||||
memHex,
|
||||
new BigNumber(dest),
|
||||
new BigNumber(source),
|
||||
new BigNumber(length),
|
||||
);
|
||||
const result = fromHex(resultStr);
|
||||
expect(result).to.deep.equal(expected);
|
||||
}),
|
||||
);
|
||||
|
||||
test([[0, 0, 0, 'copies zero bytes with overlap']]);
|
||||
|
||||
describe('copies forward', () =>
|
||||
test([
|
||||
[128, 0, 0, 'zero bytes'],
|
||||
[128, 0, 1, 'one byte'],
|
||||
[128, 0, 11, 'eleven bytes'],
|
||||
[128, 0, 31, 'thirty-one bytes'],
|
||||
[128, 0, 32, 'one word'],
|
||||
[128, 0, 64, 'two words'],
|
||||
[128, 0, 96, 'three words'],
|
||||
[128, 0, 33, 'one word and one byte'],
|
||||
[128, 0, 72, 'two words and eight bytes'],
|
||||
[128, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward within one word', () =>
|
||||
test([
|
||||
[16, 0, 0, 'zero bytes'],
|
||||
[16, 0, 1, 'one byte'],
|
||||
[16, 0, 11, 'eleven bytes'],
|
||||
[16, 0, 16, 'sixteen bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 1, 'one byte'],
|
||||
[10, 0, 11, 'eleven bytes'],
|
||||
[30, 0, 31, 'thirty-one bytes'],
|
||||
[31, 0, 32, 'one word'],
|
||||
[32, 0, 33, 'one word and one byte'],
|
||||
[71, 0, 72, 'two words and eight bytes'],
|
||||
[99, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with thirty-one bytes overlap', () =>
|
||||
test([
|
||||
[0, 0, 31, 'thirty-one bytes'],
|
||||
[1, 0, 32, 'one word'],
|
||||
[2, 0, 33, 'one word and one byte'],
|
||||
[41, 0, 72, 'two words and eight bytes'],
|
||||
[69, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with one word overlap', () =>
|
||||
test([
|
||||
[0, 0, 32, 'one word'],
|
||||
[1, 0, 33, 'one word and one byte'],
|
||||
[41, 0, 72, 'two words and eight bytes'],
|
||||
[69, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with one word and one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 33, 'one word and one byte'],
|
||||
[40, 0, 72, 'two words and eight bytes'],
|
||||
[68, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with two words overlap', () =>
|
||||
test([
|
||||
[0, 0, 64, 'two words'],
|
||||
[8, 0, 72, 'two words and eight bytes'],
|
||||
[36, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward within one word and one byte overlap', () =>
|
||||
test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']]));
|
||||
|
||||
describe('copies backward', () =>
|
||||
test([
|
||||
[0, 128, 0, 'zero bytes'],
|
||||
[0, 128, 1, 'one byte'],
|
||||
[0, 128, 11, 'eleven bytes'],
|
||||
[0, 128, 31, 'thirty-one bytes'],
|
||||
[0, 128, 32, 'one word'],
|
||||
[0, 128, 64, 'two words'],
|
||||
[0, 128, 96, 'three words'],
|
||||
[0, 128, 33, 'one word and one byte'],
|
||||
[0, 128, 72, 'two words and eight bytes'],
|
||||
[0, 128, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward within one word', () =>
|
||||
test([
|
||||
[0, 16, 0, 'zero bytes'],
|
||||
[0, 16, 1, 'one byte'],
|
||||
[0, 16, 11, 'eleven bytes'],
|
||||
[0, 16, 16, 'sixteen bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 1, 'one byte'],
|
||||
[0, 10, 11, 'eleven bytes'],
|
||||
[0, 30, 31, 'thirty-one bytes'],
|
||||
[0, 31, 32, 'one word'],
|
||||
[0, 32, 33, 'one word and one byte'],
|
||||
[0, 71, 72, 'two words and eight bytes'],
|
||||
[0, 99, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with thirty-one bytes overlap', () =>
|
||||
test([
|
||||
[0, 0, 31, 'thirty-one bytes'],
|
||||
[0, 1, 32, 'one word'],
|
||||
[0, 2, 33, 'one word and one byte'],
|
||||
[0, 41, 72, 'two words and eight bytes'],
|
||||
[0, 69, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with one word overlap', () =>
|
||||
test([
|
||||
[0, 0, 32, 'one word'],
|
||||
[0, 1, 33, 'one word and one byte'],
|
||||
[0, 41, 72, 'two words and eight bytes'],
|
||||
[0, 69, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with one word and one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 33, 'one word and one byte'],
|
||||
[0, 40, 72, 'two words and eight bytes'],
|
||||
[0, 68, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with two words overlap', () =>
|
||||
test([
|
||||
[0, 0, 64, 'two words'],
|
||||
[0, 8, 72, 'two words and eight bytes'],
|
||||
[0, 36, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward within one word and one byte overlap', () =>
|
||||
test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']]));
|
||||
});
|
||||
});
|
@@ -78,7 +78,10 @@ describe('ZRXToken', () => {
|
||||
const receiver = spender;
|
||||
const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = new BigNumber(1);
|
||||
await zrxToken.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner });
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const finalOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const finalReceiverBalance = await zrxToken.balanceOf.callAsync(receiver);
|
||||
|
||||
@@ -100,10 +103,13 @@ describe('ZRXToken', () => {
|
||||
it('should return false if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
});
|
||||
@@ -136,14 +142,20 @@ describe('ZRXToken', () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = MAX_UINT;
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
});
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
|
||||
expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
|
||||
@@ -154,11 +166,17 @@ describe('ZRXToken', () => {
|
||||
const initSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = initOwnerBalance;
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance);
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const newSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
|
||||
@@ -170,11 +188,17 @@ describe('ZRXToken', () => {
|
||||
it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer);
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
|
||||
expect(newSpenderAllowance).to.be.bignumber.equal(0);
|
||||
|
@@ -5,6 +5,10 @@
|
||||
{
|
||||
"note": "Add optional parameter shouldUseFakeGasEstimate to Web3Config",
|
||||
"pr": 622
|
||||
},
|
||||
{
|
||||
"note": "Add SolidityProfiler to EnvVars",
|
||||
"pr": 675
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -60,7 +60,7 @@ export const callbackErrorReporter = {
|
||||
done: DoneCallback,
|
||||
errMsg: string,
|
||||
): <T>(error: Error | null, value: T | undefined) => void {
|
||||
const wrapped = <T>(error: Error | null, value: T | undefined) => {
|
||||
const wrapped = <T>(error: Error | null, _value: T | undefined) => {
|
||||
if (_.isNull(error)) {
|
||||
done(new Error('Expected callback to receive an error'));
|
||||
} else {
|
||||
|
@@ -3,6 +3,7 @@ import * as process from 'process';
|
||||
|
||||
export enum EnvVars {
|
||||
SolidityCoverage = 'SOLIDITY_COVERAGE',
|
||||
SolidityProfiler = 'SOLIDITY_PROFILER',
|
||||
VerboseGanache = 'VERBOSE_GANACHE',
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,9 @@ sleep 10
|
||||
# to break when there are fewer than 3 blocks in the chain. (We have no idea
|
||||
# why, but it was consistently reproducible).
|
||||
/geth --datadir node0/ attach --exec 'eth.sendTransaction({"from": "0x5409ED021D9299bf6814279A6A1411A7e866A631", "to": "0x84bd1cfa409cb0bb9b23b8b1a33515b4ac00a0af", "value": "0x1"})'
|
||||
sleep 2
|
||||
/geth --datadir node0/ attach --exec 'eth.sendTransaction({"from": "0x5409ED021D9299bf6814279A6A1411A7e866A631", "to": "0x84bd1cfa409cb0bb9b23b8b1a33515b4ac00a0af", "value": "0x1"})'
|
||||
sleep 2
|
||||
/geth --datadir node0/ attach --exec 'eth.sendTransaction({"from": "0x5409ED021D9299bf6814279A6A1411A7e866A631", "to": "0x84bd1cfa409cb0bb9b23b8b1a33515b4ac00a0af", "value": "0x1"})'
|
||||
|
||||
# Use tail to re-attach to the log file and actually see the output.
|
||||
|
@@ -1,11 +1,21 @@
|
||||
[
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `TraceParams` interface for `debug_traceTransaction` parameters",
|
||||
"pr": 675
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Initial publish",
|
||||
"pr": "642"
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1527811200
|
||||
}
|
||||
]
|
||||
|
@@ -279,3 +279,9 @@ export enum SolidityTypes {
|
||||
export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
|
||||
logs: Array<LogWithDecodedArgs<DecodedLogArgs> | LogEntry>;
|
||||
}
|
||||
|
||||
export interface TraceParams {
|
||||
disableMemory?: boolean;
|
||||
disableStack?: boolean;
|
||||
disableStorage?: boolean;
|
||||
}
|
||||
|
@@ -169,10 +169,10 @@ export class FillScenarios {
|
||||
feeRecepientAddress: string,
|
||||
expirationTimeSeconds?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
const makerERC20ProxyData = assetProxyUtils.decodeERC20ProxyData(makerAssetData);
|
||||
const makerTokenAddress = makerERC20ProxyData.tokenAddress;
|
||||
const takerERC20ProxyData = assetProxyUtils.decodeERC20ProxyData(takerAssetData);
|
||||
const takerTokenAddress = takerERC20ProxyData.tokenAddress;
|
||||
const makerERC20AssetData = assetProxyUtils.decodeERC20AssetData(makerAssetData);
|
||||
const makerTokenAddress = makerERC20AssetData.tokenAddress;
|
||||
const takerERC20AssetData = assetProxyUtils.decodeERC20AssetData(takerAssetData);
|
||||
const takerTokenAddress = takerERC20AssetData.tokenAddress;
|
||||
await Promise.all([
|
||||
this._increaseERC20BalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||
this._increaseERC20BalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||
|
@@ -17,7 +17,7 @@
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit --timeout 10000",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'artifacts/Metacoin.json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers --backend ethers",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "0.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use AssetProxyOwner instead of MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress",
|
||||
"pr": 675
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527008794,
|
||||
"version": "0.0.6",
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -30,21 +30,7 @@
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"evm": {
|
||||
"bytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "0x",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
},
|
||||
"deployedBytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "0x",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"sources": {
|
||||
"current/protocol/Exchange/interfaces/IValidator.sol": {
|
||||
@@ -73,4 +59,4 @@
|
||||
}
|
||||
},
|
||||
"networks": {}
|
||||
}
|
||||
}
|
||||
|
18
packages/migrations/artifacts/2.0.0/IWallet.json
vendored
18
packages/migrations/artifacts/2.0.0/IWallet.json
vendored
@@ -26,21 +26,7 @@
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"evm": {
|
||||
"bytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "0x",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
},
|
||||
"deployedBytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "0x",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"sources": {
|
||||
"current/protocol/Exchange/interfaces/IWallet.sol": {
|
||||
@@ -69,4 +55,4 @@
|
||||
}
|
||||
},
|
||||
"networks": {}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
119
packages/migrations/artifacts/2.0.0/TestLibAssetProxyDecoder.json
vendored
Normal file
119
packages/migrations/artifacts/2.0.0/TestLibAssetProxyDecoder.json
vendored
Normal file
File diff suppressed because one or more lines are too long
16
packages/migrations/artifacts/2.0.0/WETH9.json
vendored
16
packages/migrations/artifacts/2.0.0/WETH9.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -31,7 +31,7 @@
|
||||
"v1":
|
||||
"artifacts/1.0.0/@(DummyERC20Token|TokenTransferProxy_v1|Exchange_v1|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|WETH9).json",
|
||||
"v2":
|
||||
"artifacts/2.0.0/@(ERC20Token|DummyERC20Token|ERC721Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|ZRXToken|WETH9|IWallet|IValidator).json"
|
||||
"artifacts/2.0.0/@(ERC20Token|DummyERC20Token|ERC721Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|AssetProxyOwner|ZRXToken|WETH9|IWallet|IValidator).json"
|
||||
}
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
|
@@ -68,8 +68,13 @@ export const runV1MigrationsAsync = async (provider: Provider, artifactsDir: str
|
||||
artifactsWriter.saveArtifact(multiSig);
|
||||
|
||||
const owner = accounts[0];
|
||||
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner });
|
||||
await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, { from: owner });
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, { from: owner }),
|
||||
);
|
||||
const addTokenGasEstimate = await tokenReg.addToken.estimateGasAsync(
|
||||
zrxToken.address,
|
||||
erc20TokenInfo[0].name,
|
||||
@@ -80,29 +85,33 @@ export const runV1MigrationsAsync = async (provider: Provider, artifactsDir: str
|
||||
{ from: owner },
|
||||
);
|
||||
const decimals = 18;
|
||||
await tokenReg.addToken.sendTransactionAsync(
|
||||
zrxToken.address,
|
||||
'0x Protocol Token',
|
||||
'ZRX',
|
||||
decimals,
|
||||
NULL_BYTES,
|
||||
NULL_BYTES,
|
||||
{
|
||||
from: owner,
|
||||
gas: addTokenGasEstimate,
|
||||
},
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tokenReg.addToken.sendTransactionAsync(
|
||||
zrxToken.address,
|
||||
'0x Protocol Token',
|
||||
'ZRX',
|
||||
decimals,
|
||||
NULL_BYTES,
|
||||
NULL_BYTES,
|
||||
{
|
||||
from: owner,
|
||||
gas: addTokenGasEstimate,
|
||||
},
|
||||
),
|
||||
);
|
||||
await tokenReg.addToken.sendTransactionAsync(
|
||||
etherToken.address,
|
||||
'Ether Token',
|
||||
'WETH',
|
||||
decimals,
|
||||
NULL_BYTES,
|
||||
NULL_BYTES,
|
||||
{
|
||||
from: owner,
|
||||
gas: addTokenGasEstimate,
|
||||
},
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tokenReg.addToken.sendTransactionAsync(
|
||||
etherToken.address,
|
||||
'Ether Token',
|
||||
'WETH',
|
||||
decimals,
|
||||
NULL_BYTES,
|
||||
NULL_BYTES,
|
||||
{
|
||||
from: owner,
|
||||
gas: addTokenGasEstimate,
|
||||
},
|
||||
),
|
||||
);
|
||||
for (const token of erc20TokenInfo) {
|
||||
const totalSupply = new BigNumber(100000000000000000000);
|
||||
@@ -115,17 +124,19 @@ export const runV1MigrationsAsync = async (provider: Provider, artifactsDir: str
|
||||
token.decimals,
|
||||
totalSupply,
|
||||
);
|
||||
await tokenReg.addToken.sendTransactionAsync(
|
||||
dummyToken.address,
|
||||
token.name,
|
||||
token.symbol,
|
||||
token.decimals,
|
||||
token.ipfsHash,
|
||||
token.swarmHash,
|
||||
{
|
||||
from: owner,
|
||||
gas: addTokenGasEstimate,
|
||||
},
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tokenReg.addToken.sendTransactionAsync(
|
||||
dummyToken.address,
|
||||
token.name,
|
||||
token.symbol,
|
||||
token.decimals,
|
||||
token.ipfsHash,
|
||||
token.swarmHash,
|
||||
{
|
||||
from: owner,
|
||||
gas: addTokenGasEstimate,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
|
||||
import * as AssetProxyOwner from '../../artifacts/2.0.0/AssetProxyOwner.json';
|
||||
import * as DummyERC20Token from '../../artifacts/2.0.0/DummyERC20Token.json';
|
||||
import * as DummyERC721Token from '../../artifacts/2.0.0/DummyERC721Token.json';
|
||||
import * as ERC20Proxy from '../../artifacts/2.0.0/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../../artifacts/2.0.0/ERC721Proxy.json';
|
||||
import * as Exchange from '../../artifacts/2.0.0/Exchange.json';
|
||||
import * as MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress from '../../artifacts/2.0.0/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.json';
|
||||
import * as WETH9 from '../../artifacts/2.0.0/WETH9.json';
|
||||
import * as ZRX from '../../artifacts/2.0.0/ZRXToken.json';
|
||||
|
||||
@@ -13,7 +13,7 @@ export const artifacts = {
|
||||
ZRX: (ZRX as any) as ContractArtifact,
|
||||
DummyERC20Token: (DummyERC20Token as any) as ContractArtifact,
|
||||
DummyERC721Token: (DummyERC721Token as any) as ContractArtifact,
|
||||
MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress: (MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress as any) as ContractArtifact,
|
||||
AssetProxyOwner: (AssetProxyOwner as any) as ContractArtifact,
|
||||
Exchange: (Exchange as any) as ContractArtifact,
|
||||
WETH9: (WETH9 as any) as ContractArtifact,
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
|
@@ -6,12 +6,12 @@ import { ArtifactWriter } from '../artifact_writer';
|
||||
import { erc20TokenInfo, erc721TokenInfo } from '../utils/token_info';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { AssetProxyOwnerContract } from './contract_wrappers/asset_proxy_owner';
|
||||
import { DummyERC20TokenContract } from './contract_wrappers/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from './contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from './contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from './contract_wrappers/e_r_c721_proxy';
|
||||
import { ExchangeContract } from './contract_wrappers/exchange';
|
||||
import { MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract } from './contract_wrappers/multi_sig_wallet_with_time_lock_except_remove_authorized_address';
|
||||
import { WETH9Contract } from './contract_wrappers/weth9';
|
||||
import { ZRXTokenContract } from './contract_wrappers/zrx_token';
|
||||
|
||||
@@ -62,34 +62,29 @@ export const runV2MigrationsAsync = async (provider: Provider, artifactsDir: str
|
||||
const secondsRequired = new BigNumber(0);
|
||||
const owner = accounts[0];
|
||||
|
||||
// TODO(leonid) use `AssetProxyOwner` after https://github.com/0xProject/0x-monorepo/pull/571 is merged
|
||||
// ERC20 Multisig
|
||||
const multiSigERC20 = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract.deployFrom0xArtifactAsync(
|
||||
artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,
|
||||
// AssetProxyOwner
|
||||
const assetProxyOwner = await AssetProxyOwnerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.AssetProxyOwner,
|
||||
provider,
|
||||
txDefaults,
|
||||
owners,
|
||||
[erc20proxy.address, erc721proxy.address],
|
||||
confirmationsRequired,
|
||||
secondsRequired,
|
||||
erc20proxy.address,
|
||||
);
|
||||
artifactsWriter.saveArtifact(multiSigERC20);
|
||||
await erc20proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner });
|
||||
await erc20proxy.transferOwnership.sendTransactionAsync(multiSigERC20.address, { from: owner });
|
||||
|
||||
// ERC721 Multisig
|
||||
const multiSigERC721 = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddressContract.deployFrom0xArtifactAsync(
|
||||
artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,
|
||||
provider,
|
||||
txDefaults,
|
||||
owners,
|
||||
confirmationsRequired,
|
||||
secondsRequired,
|
||||
erc721proxy.address,
|
||||
artifactsWriter.saveArtifact(assetProxyOwner);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20proxy.transferOwnership.sendTransactionAsync(assetProxyOwner.address, { from: owner }),
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721proxy.transferOwnership.sendTransactionAsync(assetProxyOwner.address, { from: owner }),
|
||||
);
|
||||
artifactsWriter.saveArtifact(multiSigERC721);
|
||||
await erc721proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner });
|
||||
await erc721proxy.transferOwnership.sendTransactionAsync(multiSigERC721.address, { from: owner });
|
||||
|
||||
// Dummy ERC20 tokens
|
||||
for (const token of erc20TokenInfo) {
|
||||
|
@@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"changes": [
|
||||
{
|
||||
"note": "Export parseECSignature method",
|
||||
"pr": 684
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"changes": [
|
||||
|
@@ -13,7 +13,7 @@
|
||||
"pre_build": "run-s update_artifacts generate_contract_wrappers",
|
||||
"transpile": "tsc",
|
||||
"copy_monorepo_scripts": "copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'lib/src/artifacts/@(Exchange|IWallet|IValidator).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'lib/src/artifacts/@(Exchange|IWallet|IValidator|DummyERC20Token|ERC20Proxy|ERC20Token).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json lib/src/artifacts; done;",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
@@ -29,7 +29,7 @@
|
||||
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json"
|
||||
},
|
||||
"config": {
|
||||
"contracts": "IWallet IValidator Exchange",
|
||||
"contracts": "IWallet IValidator Exchange DummyERC20Token ERC20Proxy ERC20Token",
|
||||
"postpublish": {
|
||||
"docPublishConfigs": {
|
||||
"extraFileIncludes": [
|
||||
@@ -52,6 +52,7 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/dev-utils": "^0.4.2",
|
||||
"@0xproject/migrations": "^0.0.6",
|
||||
"@0xproject/monorepo-scripts": "^0.1.20",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@types/ethereumjs-abi": "^0.6.0",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export abstract class AbstractBalanceAndProxyAllowanceFetcher {
|
||||
public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
|
||||
}
|
||||
|
@@ -0,0 +1,11 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
public abstract async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract setBalance(assetData: string, userAddress: string, balance: BigNumber): void;
|
||||
public abstract deleteBalance(assetData: string, userAddress: string): void;
|
||||
public abstract setProxyAllowance(assetData: string, userAddress: string, proxyAllowance: BigNumber): void;
|
||||
public abstract deleteProxyAllowance(assetData: string, userAddress: string): void;
|
||||
public abstract deleteAll(): void;
|
||||
}
|
@@ -1,10 +1,14 @@
|
||||
import { Artifact } from '@0xproject/types';
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
|
||||
import * as DummyERC20Token from './artifacts/DummyERC20Token.json';
|
||||
import * as ERC20Proxy from './artifacts/ERC20Proxy.json';
|
||||
import * as Exchange from './artifacts/Exchange.json';
|
||||
import * as IValidator from './artifacts/IValidator.json';
|
||||
import * as IWallet from './artifacts/IWallet.json';
|
||||
export const artifacts = {
|
||||
Exchange: (Exchange as any) as Artifact,
|
||||
IWallet: (IWallet as any) as Artifact,
|
||||
IValidator: (IValidator as any) as Artifact,
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
DummyERC20Token: (DummyERC20Token as any) as ContractArtifact,
|
||||
Exchange: (Exchange as any) as ContractArtifact,
|
||||
IWallet: (IWallet as any) as ContractArtifact,
|
||||
IValidator: (IValidator as any) as ContractArtifact,
|
||||
};
|
||||
|
@@ -1,10 +1,15 @@
|
||||
import { AssetProxyId, ERC20ProxyData, ERC721ProxyData, ProxyData } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0xproject/types';
|
||||
import { BigNumber, NULL_BYTES } from '@0xproject/utils';
|
||||
import BN = require('bn.js');
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
const ERC20_PROXY_METADATA_BYTE_LENGTH = 21;
|
||||
const ERC721_PROXY_METADATA_BYTE_LENGTH = 53;
|
||||
const ERC20_ASSET_DATA_BYTE_LENGTH = 21;
|
||||
const ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH = 53;
|
||||
const ASSET_DATA_ADDRESS_OFFSET = 0;
|
||||
const ERC721_ASSET_DATA_TOKEN_ID_OFFSET = 20;
|
||||
const ERC721_ASSET_DATA_RECEIVER_DATA_LENGTH_OFFSET = 52;
|
||||
const ERC721_ASSET_DATA_RECEIVER_DATA_OFFSET = 84;
|
||||
|
||||
export const assetProxyUtils = {
|
||||
encodeAssetProxyId(assetProxyId: AssetProxyId): Buffer {
|
||||
@@ -40,23 +45,24 @@ export const assetProxyUtils = {
|
||||
const value = new BigNumber(formattedValue, 16);
|
||||
return value;
|
||||
},
|
||||
encodeERC20ProxyData(tokenAddress: string): string {
|
||||
encodeERC20AssetData(tokenAddress: string): string {
|
||||
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC20);
|
||||
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress);
|
||||
const encodedMetadata = Buffer.concat([encodedAddress, encodedAssetProxyId]);
|
||||
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata);
|
||||
return encodedMetadataHex;
|
||||
const encodedAssetData = Buffer.concat([encodedAddress, encodedAssetProxyId]);
|
||||
const encodedAssetDataHex = ethUtil.bufferToHex(encodedAssetData);
|
||||
return encodedAssetDataHex;
|
||||
},
|
||||
decodeERC20ProxyData(proxyData: string): ERC20ProxyData {
|
||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||
if (encodedProxyMetadata.byteLength !== ERC20_PROXY_METADATA_BYTE_LENGTH) {
|
||||
decodeERC20AssetData(proxyData: string): ERC20AssetData {
|
||||
const encodedAssetData = ethUtil.toBuffer(proxyData);
|
||||
if (encodedAssetData.byteLength !== ERC20_ASSET_DATA_BYTE_LENGTH) {
|
||||
throw new Error(
|
||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 21. Got ${
|
||||
encodedProxyMetadata.byteLength
|
||||
encodedAssetData.byteLength
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const encodedAssetProxyId = encodedProxyMetadata.slice(-1);
|
||||
const assetProxyIdOffset = encodedAssetData.byteLength - 1;
|
||||
const encodedAssetProxyId = encodedAssetData.slice(assetProxyIdOffset);
|
||||
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
|
||||
if (assetProxyId !== AssetProxyId.ERC20) {
|
||||
throw new Error(
|
||||
@@ -65,33 +71,45 @@ export const assetProxyUtils = {
|
||||
}), but got ${assetProxyId}`,
|
||||
);
|
||||
}
|
||||
const addressOffset = ERC20_PROXY_METADATA_BYTE_LENGTH - 1;
|
||||
const encodedTokenAddress = encodedProxyMetadata.slice(0, addressOffset);
|
||||
const encodedTokenAddress = encodedAssetData.slice(ASSET_DATA_ADDRESS_OFFSET, assetProxyIdOffset);
|
||||
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
||||
const erc20ProxyData = {
|
||||
const erc20AssetData = {
|
||||
assetProxyId,
|
||||
tokenAddress,
|
||||
};
|
||||
return erc20ProxyData;
|
||||
return erc20AssetData;
|
||||
},
|
||||
encodeERC721ProxyData(tokenAddress: string, tokenId: BigNumber): string {
|
||||
encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber, receiverData?: string): string {
|
||||
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC721);
|
||||
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress);
|
||||
const encodedTokenId = assetProxyUtils.encodeUint256(tokenId);
|
||||
const encodedMetadata = Buffer.concat([encodedAddress, encodedTokenId, encodedAssetProxyId]);
|
||||
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata);
|
||||
return encodedMetadataHex;
|
||||
let encodedAssetData = Buffer.concat([encodedAddress, encodedTokenId]);
|
||||
if (!_.isUndefined(receiverData)) {
|
||||
const encodedReceiverData = ethUtil.toBuffer(receiverData);
|
||||
const receiverDataLength = new BigNumber(encodedReceiverData.byteLength);
|
||||
const encodedReceiverDataLength = assetProxyUtils.encodeUint256(receiverDataLength);
|
||||
encodedAssetData = Buffer.concat([encodedAssetData, encodedReceiverDataLength, encodedReceiverData]);
|
||||
}
|
||||
encodedAssetData = Buffer.concat([encodedAssetData, encodedAssetProxyId]);
|
||||
const encodedAssetDataHex = ethUtil.bufferToHex(encodedAssetData);
|
||||
return encodedAssetDataHex;
|
||||
},
|
||||
decodeERC721ProxyData(proxyData: string): ERC721ProxyData {
|
||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||
if (encodedProxyMetadata.byteLength !== ERC721_PROXY_METADATA_BYTE_LENGTH) {
|
||||
decodeERC721AssetData(assetData: string): ERC721AssetData {
|
||||
const encodedAssetData = ethUtil.toBuffer(assetData);
|
||||
if (encodedAssetData.byteLength < ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH) {
|
||||
throw new Error(
|
||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 53. Got ${
|
||||
encodedProxyMetadata.byteLength
|
||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least 53. Got ${
|
||||
encodedAssetData.byteLength
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const encodedAssetProxyId = encodedProxyMetadata.slice(-1);
|
||||
|
||||
const encodedTokenAddress = encodedAssetData.slice(
|
||||
ASSET_DATA_ADDRESS_OFFSET,
|
||||
ERC721_ASSET_DATA_TOKEN_ID_OFFSET,
|
||||
);
|
||||
const proxyIdOffset = encodedAssetData.byteLength - 1;
|
||||
const encodedAssetProxyId = encodedAssetData.slice(proxyIdOffset);
|
||||
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
|
||||
if (assetProxyId !== AssetProxyId.ERC721) {
|
||||
throw new Error(
|
||||
@@ -100,50 +118,63 @@ export const assetProxyUtils = {
|
||||
}), but got ${assetProxyId}`,
|
||||
);
|
||||
}
|
||||
const addressOffset = ERC20_PROXY_METADATA_BYTE_LENGTH - 1;
|
||||
const encodedTokenAddress = encodedProxyMetadata.slice(0, addressOffset);
|
||||
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
||||
const tokenIdOffset = ERC721_PROXY_METADATA_BYTE_LENGTH - 1;
|
||||
const encodedTokenId = encodedProxyMetadata.slice(addressOffset, tokenIdOffset);
|
||||
const encodedTokenId = encodedAssetData.slice(
|
||||
ERC721_ASSET_DATA_TOKEN_ID_OFFSET,
|
||||
ERC721_ASSET_DATA_RECEIVER_DATA_LENGTH_OFFSET,
|
||||
);
|
||||
const tokenId = assetProxyUtils.decodeUint256(encodedTokenId);
|
||||
const erc721ProxyData = {
|
||||
let receiverData = NULL_BYTES;
|
||||
const lengthUpToReceiverDataLength = ERC721_ASSET_DATA_RECEIVER_DATA_LENGTH_OFFSET + 1;
|
||||
if (encodedAssetData.byteLength > lengthUpToReceiverDataLength) {
|
||||
const encodedReceiverDataLength = encodedAssetData.slice(
|
||||
ERC721_ASSET_DATA_RECEIVER_DATA_LENGTH_OFFSET,
|
||||
ERC721_ASSET_DATA_RECEIVER_DATA_OFFSET,
|
||||
);
|
||||
const receiverDataLength = assetProxyUtils.decodeUint256(encodedReceiverDataLength);
|
||||
const lengthUpToReceiverData = ERC721_ASSET_DATA_RECEIVER_DATA_OFFSET + 1;
|
||||
const expectedReceiverDataLength = new BigNumber(encodedAssetData.byteLength - lengthUpToReceiverData);
|
||||
if (!receiverDataLength.equals(expectedReceiverDataLength)) {
|
||||
throw new Error(
|
||||
`Data length (${receiverDataLength}) does not match actual length of data (${expectedReceiverDataLength})`,
|
||||
);
|
||||
}
|
||||
const encodedReceiverData = encodedAssetData.slice(
|
||||
ERC721_ASSET_DATA_RECEIVER_DATA_OFFSET,
|
||||
receiverDataLength.add(ERC721_ASSET_DATA_RECEIVER_DATA_OFFSET).toNumber(),
|
||||
);
|
||||
receiverData = ethUtil.bufferToHex(encodedReceiverData);
|
||||
}
|
||||
const erc721AssetData: ERC721AssetData = {
|
||||
assetProxyId,
|
||||
tokenAddress,
|
||||
tokenId,
|
||||
receiverData,
|
||||
};
|
||||
return erc721ProxyData;
|
||||
return erc721AssetData;
|
||||
},
|
||||
decodeProxyDataId(proxyData: string): AssetProxyId {
|
||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||
if (encodedProxyMetadata.byteLength < 1) {
|
||||
decodeAssetDataId(assetData: string): AssetProxyId {
|
||||
const encodedAssetData = ethUtil.toBuffer(assetData);
|
||||
if (encodedAssetData.byteLength < 1) {
|
||||
throw new Error(
|
||||
`Could not decode Proxy Data. Expected length of encoded data to be at least 1. Got ${
|
||||
encodedProxyMetadata.byteLength
|
||||
encodedAssetData.byteLength
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const encodedAssetProxyId = encodedProxyMetadata.slice(-1);
|
||||
const encodedAssetProxyId = encodedAssetData.slice(-1);
|
||||
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
|
||||
return assetProxyId;
|
||||
},
|
||||
decodeProxyData(proxyData: string): ProxyData {
|
||||
const assetProxyId = assetProxyUtils.decodeProxyDataId(proxyData);
|
||||
decodeAssetData(assetData: string): ERC20AssetData | ERC721AssetData {
|
||||
const assetProxyId = assetProxyUtils.decodeAssetDataId(assetData);
|
||||
switch (assetProxyId) {
|
||||
case AssetProxyId.ERC20:
|
||||
const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(proxyData);
|
||||
const generalizedERC20ProxyData = {
|
||||
assetProxyId,
|
||||
tokenAddress: erc20ProxyData.tokenAddress,
|
||||
};
|
||||
return generalizedERC20ProxyData;
|
||||
const erc20AssetData = assetProxyUtils.decodeERC20AssetData(assetData);
|
||||
return erc20AssetData;
|
||||
case AssetProxyId.ERC721:
|
||||
const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(proxyData);
|
||||
const generaliedERC721ProxyData = {
|
||||
assetProxyId,
|
||||
tokenAddress: erc721ProxyData.tokenAddress,
|
||||
data: erc721ProxyData.tokenId,
|
||||
};
|
||||
return generaliedERC721ProxyData;
|
||||
const erc721AssetData = assetProxyUtils.decodeERC721AssetData(assetData);
|
||||
return erc721AssetData;
|
||||
default:
|
||||
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
|
||||
}
|
||||
|
@@ -1,3 +1,8 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
||||
TESTRPC_NETWORK_ID: 50,
|
||||
};
|
||||
|
113
packages/order-utils/src/exchange_transfer_simulator.ts
Normal file
113
packages/order-utils/src/exchange_transfer_simulator.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { ExchangeContractErrs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { constants } from './constants';
|
||||
import { TradeSide, TransferType } from './types';
|
||||
|
||||
enum FailureReason {
|
||||
Balance = 'balance',
|
||||
ProxyAllowance = 'proxyAllowance',
|
||||
}
|
||||
|
||||
const ERR_MSG_MAPPING = {
|
||||
[FailureReason.Balance]: {
|
||||
[TradeSide.Maker]: {
|
||||
[TransferType.Trade]: ExchangeContractErrs.InsufficientMakerBalance,
|
||||
[TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeBalance,
|
||||
},
|
||||
[TradeSide.Taker]: {
|
||||
[TransferType.Trade]: ExchangeContractErrs.InsufficientTakerBalance,
|
||||
[TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeBalance,
|
||||
},
|
||||
},
|
||||
[FailureReason.ProxyAllowance]: {
|
||||
[TradeSide.Maker]: {
|
||||
[TransferType.Trade]: ExchangeContractErrs.InsufficientMakerAllowance,
|
||||
[TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeAllowance,
|
||||
},
|
||||
[TradeSide.Taker]: {
|
||||
[TransferType.Trade]: ExchangeContractErrs.InsufficientTakerAllowance,
|
||||
[TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeAllowance,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export class ExchangeTransferSimulator {
|
||||
private _store: AbstractBalanceAndProxyAllowanceLazyStore;
|
||||
private static _throwValidationError(
|
||||
failureReason: FailureReason,
|
||||
tradeSide: TradeSide,
|
||||
transferType: TransferType,
|
||||
): never {
|
||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) {
|
||||
this._store = store;
|
||||
}
|
||||
/**
|
||||
* Simulates transferFrom call performed by a proxy
|
||||
* @param assetData Data of the asset being transferred. Includes
|
||||
* it's identifying information and assetType,
|
||||
* e.g address for ERC20, address & tokenId for ERC721
|
||||
* @param from Owner of the transferred tokens
|
||||
* @param to Recipient of the transferred tokens
|
||||
* @param amountInBaseUnits The amount of tokens being transferred
|
||||
* @param tradeSide Is Maker/Taker transferring
|
||||
* @param transferType Is it a fee payment or a value transfer
|
||||
*/
|
||||
public async transferFromAsync(
|
||||
assetData: string,
|
||||
from: string,
|
||||
to: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
tradeSide: TradeSide,
|
||||
transferType: TransferType,
|
||||
): Promise<void> {
|
||||
// HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
|
||||
// allowances for the taker. We do however, want to increase the balance of the maker since the maker
|
||||
// might be relying on those funds to fill subsequent orders or pay the order's fees.
|
||||
if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
|
||||
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
|
||||
return;
|
||||
}
|
||||
const balance = await this._store.getBalanceAsync(assetData, from);
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
|
||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
||||
}
|
||||
if (balance.lessThan(amountInBaseUnits)) {
|
||||
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||
}
|
||||
await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
|
||||
await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
|
||||
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
|
||||
}
|
||||
private async _decreaseProxyAllowanceAsync(
|
||||
assetData: string,
|
||||
userAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, userAddress);
|
||||
if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this._store.setProxyAllowance(assetData, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
private async _increaseBalanceAsync(
|
||||
assetData: string,
|
||||
userAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(assetData, userAddress);
|
||||
this._store.setBalance(assetData, userAddress, balance.plus(amountInBaseUnits));
|
||||
}
|
||||
private async _decreaseBalanceAsync(
|
||||
assetData: string,
|
||||
userAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(assetData, userAddress);
|
||||
this._store.setBalance(assetData, userAddress, balance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@ export {
|
||||
isValidECSignature,
|
||||
ecSignOrderHashAsync,
|
||||
addSignedMessagePrefix,
|
||||
parseECSignature,
|
||||
} from './signature_utils';
|
||||
export { orderFactory } from './order_factory';
|
||||
export { constants } from './constants';
|
||||
@@ -18,3 +19,5 @@ export { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_f
|
||||
export { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
||||
export { OrderStateUtils } from './order_state_utils';
|
||||
export { assetProxyUtils } from './asset_proxy_utils';
|
||||
export { OrderValidationUtils } from './order_validation_utils';
|
||||
export { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||
|
@@ -79,7 +79,7 @@ export class OrderStateUtils {
|
||||
}
|
||||
public async getOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> {
|
||||
const zrxTokenAddress = this._orderFilledCancelledFetcher.getZRXTokenAddress();
|
||||
const makerProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrder.makerAssetData);
|
||||
const makerProxyData = assetProxyUtils.decodeERC20AssetData(signedOrder.makerAssetData);
|
||||
const makerAssetAddress = makerProxyData.tokenAddress;
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const makerBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
||||
@@ -111,7 +111,7 @@ export class OrderStateUtils {
|
||||
const transferrableMakerAssetAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
||||
const transferrableFeeAssetAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
||||
|
||||
const zrxAssetData = assetProxyUtils.encodeERC20ProxyData(zrxTokenAddress);
|
||||
const zrxAssetData = assetProxyUtils.encodeERC20AssetData(zrxTokenAddress);
|
||||
const isMakerAssetZRX = signedOrder.makerAssetData === zrxAssetData;
|
||||
const remainingFillableCalculator = new RemainingFillableCalculator(
|
||||
signedOrder.makerFee,
|
||||
|
231
packages/order-utils/src/order_validation_utils.ts
Normal file
231
packages/order-utils/src/order_validation_utils.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
import { ExchangeContractErrs, Order, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { OrderError, TradeSide, TransferType } from './types';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||
import { ExchangeContract } from './generated_contract_wrappers/exchange';
|
||||
import { orderHashUtils } from './order_hash';
|
||||
import { isValidSignatureAsync } from './signature_utils';
|
||||
import { utils } from './utils';
|
||||
|
||||
export class OrderValidationUtils {
|
||||
private _exchangeContract: ExchangeContract;
|
||||
// TODO: Write some tests for the function
|
||||
// const numerator = new BigNumber(20);
|
||||
// const denominator = new BigNumber(999);
|
||||
// const target = new BigNumber(50);
|
||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||
public static isRoundingError(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
|
||||
// Solidity's mulmod() in JS
|
||||
// Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions
|
||||
if (denominator.eq(0)) {
|
||||
throw new Error('denominator cannot be 0');
|
||||
}
|
||||
const remainder = target.mul(numerator).mod(denominator);
|
||||
if (remainder.eq(0)) {
|
||||
return false; // no rounding error
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const errPercentageTimes1000000 = remainder.mul(1000000).div(numerator.mul(target));
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const isError = errPercentageTimes1000000.gt(1000);
|
||||
return isError;
|
||||
}
|
||||
public static validateCancelOrderThrowIfInvalid(
|
||||
order: Order,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
filledTakerTokenAmount: BigNumber,
|
||||
): void {
|
||||
if (cancelTakerTokenAmount.eq(0)) {
|
||||
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
}
|
||||
if (order.takerAssetAmount.eq(filledTakerTokenAmount)) {
|
||||
throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
||||
}
|
||||
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||
if (order.expirationTimeSeconds.lessThan(currentUnixTimestampSec)) {
|
||||
throw new Error(ExchangeContractErrs.OrderCancelExpired);
|
||||
}
|
||||
}
|
||||
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
senderAddress: string,
|
||||
zrxTokenAddress: string,
|
||||
): Promise<void> {
|
||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
signedOrder.makerAssetData,
|
||||
signedOrder.makerAddress,
|
||||
senderAddress,
|
||||
fillMakerTokenAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
signedOrder.takerAssetData,
|
||||
senderAddress,
|
||||
signedOrder.makerAddress,
|
||||
fillTakerTokenAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerFee,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
zrxTokenAddress,
|
||||
signedOrder.makerAddress,
|
||||
signedOrder.feeRecipientAddress,
|
||||
makerFeeAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.takerFee,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
zrxTokenAddress,
|
||||
senderAddress,
|
||||
signedOrder.feeRecipientAddress,
|
||||
takerFeeAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
}
|
||||
private static _validateRemainingFillAmountNotZeroOrThrow(
|
||||
takerAssetAmount: BigNumber,
|
||||
filledTakerTokenAmount: BigNumber,
|
||||
): void {
|
||||
if (takerAssetAmount.eq(filledTakerTokenAmount)) {
|
||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
}
|
||||
}
|
||||
private static _validateOrderNotExpiredOrThrow(expirationTimeSeconds: BigNumber): void {
|
||||
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||
if (expirationTimeSeconds.lessThan(currentUnixTimestampSec)) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
||||
}
|
||||
}
|
||||
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
const fillMakerTokenAmount = numerator
|
||||
.mul(target)
|
||||
.div(denominator)
|
||||
.round(0);
|
||||
return fillMakerTokenAmount;
|
||||
}
|
||||
constructor(exchangeContract: ExchangeContract) {
|
||||
this._exchangeContract = exchangeContract;
|
||||
}
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
signedOrder: SignedOrder,
|
||||
zrxTokenAddress: string,
|
||||
expectedFillTakerTokenAmount?: BigNumber,
|
||||
): Promise<void> {
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const filledTakerTokenAmount = await this._exchangeContract.filled.callAsync(orderHash);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerAssetAmount,
|
||||
filledTakerTokenAmount,
|
||||
);
|
||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationTimeSeconds);
|
||||
let fillTakerTokenAmount = signedOrder.takerAssetAmount.minus(filledTakerTokenAmount);
|
||||
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
|
||||
fillTakerTokenAmount = expectedFillTakerTokenAmount;
|
||||
}
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
public async validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
provider: Provider,
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
zrxTokenAddress: string,
|
||||
): Promise<BigNumber> {
|
||||
if (fillTakerTokenAmount.eq(0)) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
|
||||
}
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const isValid = await isValidSignatureAsync(
|
||||
provider,
|
||||
orderHash,
|
||||
signedOrder.signature,
|
||||
signedOrder.makerAddress,
|
||||
);
|
||||
if (!isValid) {
|
||||
throw new Error(OrderError.InvalidSignature);
|
||||
}
|
||||
const filledTakerTokenAmount = await this._exchangeContract.filled.callAsync(orderHash);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerAssetAmount,
|
||||
filledTakerTokenAmount,
|
||||
);
|
||||
if (signedOrder.takerAddress !== constants.NULL_ADDRESS && signedOrder.takerAddress !== takerAddress) {
|
||||
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||
}
|
||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationTimeSeconds);
|
||||
const remainingTakerTokenAmount = signedOrder.takerAssetAmount.minus(filledTakerTokenAmount);
|
||||
const desiredFillTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount)
|
||||
? remainingTakerTokenAmount
|
||||
: fillTakerTokenAmount;
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
desiredFillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingError(
|
||||
filledTakerTokenAmount,
|
||||
signedOrder.takerAssetAmount,
|
||||
signedOrder.makerAssetAmount,
|
||||
);
|
||||
if (wouldRoundingErrorOccur) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||
}
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
provider: Provider,
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
zrxTokenAddress: string,
|
||||
): Promise<void> {
|
||||
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
provider,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
|
||||
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -90,7 +90,7 @@ export async function isValidPresignedSignatureAsync(
|
||||
data: string,
|
||||
signerAddress: string,
|
||||
): Promise<boolean> {
|
||||
const exchangeContract = new ExchangeContract(artifacts.Exchange.abi, signerAddress, provider);
|
||||
const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
|
||||
const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress);
|
||||
return isValid;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ export async function isValidWalletSignatureAsync(
|
||||
): Promise<boolean> {
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const signatureWithoutType = signature.slice(-2);
|
||||
const walletContract = new IWalletContract(artifacts.IWallet.abi, signerAddress, provider);
|
||||
const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider);
|
||||
const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType);
|
||||
return isValid;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ export async function isValidValidatorSignatureAsync(
|
||||
signerAddress: string,
|
||||
): Promise<boolean> {
|
||||
const validatorSignature = parseValidatorSignature(signature);
|
||||
const exchangeContract = new ExchangeContract(artifacts.Exchange.abi, signerAddress, provider);
|
||||
const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
|
||||
const isValidatorApproved = await exchangeContract.allowedValidators.callAsync(
|
||||
signerAddress,
|
||||
validatorSignature.validatorAddress,
|
||||
@@ -138,7 +138,7 @@ export async function isValidValidatorSignatureAsync(
|
||||
throw new Error(`Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`);
|
||||
}
|
||||
|
||||
const validatorContract = new IValidatorContract(artifacts.IValidator.abi, signerAddress, provider);
|
||||
const validatorContract = new IValidatorContract(artifacts.IValidator.compilerOutput.abi, signerAddress, provider);
|
||||
const isValid = await validatorContract.isValidSignature.callAsync(
|
||||
data,
|
||||
signerAddress,
|
||||
@@ -260,12 +260,12 @@ export function addSignedMessagePrefix(message: string, messagePrefixType: Messa
|
||||
}
|
||||
}
|
||||
|
||||
function hashTrezorPersonalMessage(message: Buffer): Buffer {
|
||||
const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.length));
|
||||
return ethUtil.sha3(Buffer.concat([prefix, message]));
|
||||
}
|
||||
|
||||
function parseECSignature(signature: string): ECSignature {
|
||||
/**
|
||||
* Parse a 0x protocol hex-encoded signature string into it's ECSignature components
|
||||
* @param signature A hex encoded ecSignature 0x Protocol signature
|
||||
* @return An ECSignature object with r,s,v parameters
|
||||
*/
|
||||
export function parseECSignature(signature: string): ECSignature {
|
||||
const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor];
|
||||
assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes);
|
||||
|
||||
@@ -276,6 +276,11 @@ function parseECSignature(signature: string): ECSignature {
|
||||
return ecSignature;
|
||||
}
|
||||
|
||||
function hashTrezorPersonalMessage(message: Buffer): Buffer {
|
||||
const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.length));
|
||||
return ethUtil.sha3(Buffer.concat([prefix, message]));
|
||||
}
|
||||
|
||||
function parseValidatorSignature(signature: string): ValidatorSignature {
|
||||
assert.isOneOfExpectedSignatureTypes(signature, [SignatureType.Validator]);
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
|
@@ -0,0 +1,81 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceFetcher } from '../abstract/abstract_balance_and_proxy_allowance_fetcher';
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
|
||||
/**
|
||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||
*/
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
private _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher;
|
||||
private _balance: {
|
||||
[assetData: string]: {
|
||||
[userAddress: string]: BigNumber;
|
||||
};
|
||||
};
|
||||
private _proxyAllowance: {
|
||||
[assetData: string]: {
|
||||
[userAddress: string]: BigNumber;
|
||||
};
|
||||
};
|
||||
constructor(token: AbstractBalanceAndProxyAllowanceFetcher) {
|
||||
this._balanceAndProxyAllowanceFetcher = token;
|
||||
this._balance = {};
|
||||
this._proxyAllowance = {};
|
||||
}
|
||||
public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this._balance[assetData]) || _.isUndefined(this._balance[assetData][userAddress])) {
|
||||
const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, userAddress);
|
||||
this.setBalance(assetData, userAddress, balance);
|
||||
}
|
||||
const cachedBalance = this._balance[assetData][userAddress];
|
||||
return cachedBalance;
|
||||
}
|
||||
public setBalance(assetData: string, userAddress: string, balance: BigNumber): void {
|
||||
if (_.isUndefined(this._balance[assetData])) {
|
||||
this._balance[assetData] = {};
|
||||
}
|
||||
this._balance[assetData][userAddress] = balance;
|
||||
}
|
||||
public deleteBalance(assetData: string, userAddress: string): void {
|
||||
if (!_.isUndefined(this._balance[assetData])) {
|
||||
delete this._balance[assetData][userAddress];
|
||||
if (_.isEmpty(this._balance[assetData])) {
|
||||
delete this._balance[assetData];
|
||||
}
|
||||
}
|
||||
}
|
||||
public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
|
||||
if (
|
||||
_.isUndefined(this._proxyAllowance[assetData]) ||
|
||||
_.isUndefined(this._proxyAllowance[assetData][userAddress])
|
||||
) {
|
||||
const proxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
||||
assetData,
|
||||
userAddress,
|
||||
);
|
||||
this.setProxyAllowance(assetData, userAddress, proxyAllowance);
|
||||
}
|
||||
const cachedProxyAllowance = this._proxyAllowance[assetData][userAddress];
|
||||
return cachedProxyAllowance;
|
||||
}
|
||||
public setProxyAllowance(assetData: string, userAddress: string, proxyAllowance: BigNumber): void {
|
||||
if (_.isUndefined(this._proxyAllowance[assetData])) {
|
||||
this._proxyAllowance[assetData] = {};
|
||||
}
|
||||
this._proxyAllowance[assetData][userAddress] = proxyAllowance;
|
||||
}
|
||||
public deleteProxyAllowance(assetData: string, userAddress: string): void {
|
||||
if (!_.isUndefined(this._proxyAllowance[assetData])) {
|
||||
delete this._proxyAllowance[assetData][userAddress];
|
||||
if (_.isEmpty(this._proxyAllowance[assetData])) {
|
||||
delete this._proxyAllowance[assetData];
|
||||
}
|
||||
}
|
||||
}
|
||||
public deleteAll(): void {
|
||||
this._balance = {};
|
||||
this._proxyAllowance = {};
|
||||
}
|
||||
}
|
@@ -23,3 +23,13 @@ export interface MessagePrefixOpts {
|
||||
prefixType: MessagePrefixType;
|
||||
shouldAddPrefixBeforeCallingEthSign: boolean;
|
||||
}
|
||||
|
||||
export enum TradeSide {
|
||||
Maker = 'maker',
|
||||
Taker = 'taker',
|
||||
}
|
||||
|
||||
export enum TransferType {
|
||||
Trade = 'trade',
|
||||
Fee = 'fee',
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const utils = {
|
||||
getSignatureTypeIndexIfExists(signature: string): number {
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
@@ -6,4 +8,8 @@ export const utils = {
|
||||
const signatureTypeInt = parseInt(signatureTypeHex, base);
|
||||
return signatureTypeInt;
|
||||
},
|
||||
getCurrentUnixTimestampSec(): BigNumber {
|
||||
const milisecondsInSecond = 1000;
|
||||
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
||||
},
|
||||
};
|
||||
|
177
packages/order-utils/test/exchange_transfer_simulator_test.ts
Normal file
177
packages/order-utils/test/exchange_transfer_simulator_test.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { ExchangeContractErrs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { artifacts } from '../src/artifacts';
|
||||
import { constants } from '../src/constants';
|
||||
import { ExchangeTransferSimulator } from '../src/exchange_transfer_simulator';
|
||||
import { DummyERC20TokenContract } from '../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC20TokenContract } from '../src/generated_contract_wrappers/e_r_c20_token';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/store/balance_and_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './utils/simple_erc20_balance_and_proxy_allowance_fetcher';
|
||||
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('ExchangeTransferSimulator', async () => {
|
||||
const transferAmount = new BigNumber(5);
|
||||
let userAddresses: string[];
|
||||
let dummyERC20Token: DummyERC20TokenContract;
|
||||
let coinbase: string;
|
||||
let sender: string;
|
||||
let recipient: string;
|
||||
let exampleTokenAddress: string;
|
||||
let exchangeTransferSimulator: ExchangeTransferSimulator;
|
||||
let txHash: string;
|
||||
let erc20ProxyAddress: string;
|
||||
before(async function(): Promise<void> {
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
|
||||
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
[coinbase, sender, recipient] = userAddresses;
|
||||
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
|
||||
const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ERC20Proxy,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
erc20ProxyAddress = erc20Proxy.address;
|
||||
|
||||
const totalSupply = new BigNumber(100000000000000000000);
|
||||
const name = 'Test';
|
||||
const symbol = 'TST';
|
||||
const decimals = new BigNumber(18);
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
dummyERC20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.DummyERC20Token,
|
||||
provider,
|
||||
txDefaults,
|
||||
name,
|
||||
symbol,
|
||||
decimals,
|
||||
totalSupply,
|
||||
);
|
||||
|
||||
exampleTokenAddress = dummyERC20Token.address;
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('#transferFromAsync', function(): void {
|
||||
// HACK: For some reason these tests need a slightly longer timeout
|
||||
const mochaTestTimeoutMs = 3000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
|
||||
beforeEach(() => {
|
||||
const simpleERC20BalanceAndProxyAllowanceFetcher = new SimpleERC20BalanceAndProxyAllowanceFetcher(
|
||||
(dummyERC20Token as any) as ERC20TokenContract,
|
||||
erc20ProxyAddress,
|
||||
);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
simpleERC20BalanceAndProxyAllowanceFetcher,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
});
|
||||
it("throws if the user doesn't have enough allowance", async () => {
|
||||
return expect(
|
||||
exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
|
||||
});
|
||||
it("throws if the user doesn't have enough balance", async () => {
|
||||
txHash = await dummyERC20Token.approve.sendTransactionAsync(erc20ProxyAddress, transferAmount, {
|
||||
from: sender,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
return expect(
|
||||
exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
||||
});
|
||||
it('updates balances and proxyAllowance after transfer', async () => {
|
||||
txHash = await dummyERC20Token.transfer.sendTransactionAsync(sender, transferAmount, {
|
||||
from: coinbase,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
|
||||
txHash = await dummyERC20Token.approve.sendTransactionAsync(erc20ProxyAddress, transferAmount, {
|
||||
from: sender,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const store = (exchangeTransferSimulator as any)._store;
|
||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
expect(senderBalance).to.be.bignumber.equal(0);
|
||||
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
||||
expect(senderProxyAllowance).to.be.bignumber.equal(0);
|
||||
});
|
||||
it("doesn't update proxyAllowance after transfer if unlimited", async () => {
|
||||
txHash = await dummyERC20Token.transfer.sendTransactionAsync(sender, transferAmount, {
|
||||
from: coinbase,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
txHash = await dummyERC20Token.approve.sendTransactionAsync(
|
||||
erc20ProxyAddress,
|
||||
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||
{
|
||||
from: sender,
|
||||
},
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const store = (exchangeTransferSimulator as any)._store;
|
||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
expect(senderBalance).to.be.bignumber.equal(0);
|
||||
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
||||
expect(senderProxyAllowance).to.be.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||
});
|
||||
});
|
||||
});
|
70
packages/order-utils/test/order_validation_utils_test.ts
Normal file
70
packages/order-utils/test/order_validation_utils_test.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
|
||||
import { OrderValidationUtils } from '../src/order_validation_utils';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
describe('OrderValidationUtils', () => {
|
||||
describe('#isRoundingError', () => {
|
||||
it('should return false if there is a rounding error of 0.1%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(999);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false if there is a rounding of 0.09%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9991);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
|
||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9989);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
|
||||
it('should return true if there is a rounding error > 0.1%', async () => {
|
||||
const numerator = new BigNumber(3);
|
||||
const denominator = new BigNumber(7);
|
||||
const target = new BigNumber(10);
|
||||
// rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when there is no rounding error', async () => {
|
||||
const numerator = new BigNumber(1);
|
||||
const denominator = new BigNumber(2);
|
||||
const target = new BigNumber(10);
|
||||
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false when there is rounding error <= 0.1%', async () => {
|
||||
// randomly generated numbers
|
||||
const numerator = new BigNumber(76564);
|
||||
const denominator = new BigNumber(676373677);
|
||||
const target = new BigNumber(105762562);
|
||||
// rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) /
|
||||
// (76564*105762562/676373677) = 0.0007%
|
||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user