Merge pull request #1363 from 0xProject/feat/order-utils/abiEncoder
Add MAP support to order-utils, order-watcher, and types
This commit is contained in:
commit
3cdb85606a
@ -715,7 +715,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
||||||
const amounts = [erc20Amount];
|
const amounts = [erc20Amount];
|
||||||
const nestedAssetData = [erc20AssetData];
|
const nestedAssetData = [erc20AssetData];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -778,7 +778,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
||||||
const amounts = [erc20Amount1, erc20Amount2];
|
const amounts = [erc20Amount1, erc20Amount2];
|
||||||
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
|
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -811,7 +811,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
|
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
|
||||||
const amounts = [erc20Amount1, erc20Amount2];
|
const amounts = [erc20Amount1, erc20Amount2];
|
||||||
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
|
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -849,7 +849,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
||||||
const amounts = [erc721Amount];
|
const amounts = [erc721Amount];
|
||||||
const nestedAssetData = [erc721AssetData];
|
const nestedAssetData = [erc721AssetData];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -881,7 +881,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721Amount = new BigNumber(1);
|
const erc721Amount = new BigNumber(1);
|
||||||
const amounts = [erc721Amount, erc721Amount];
|
const amounts = [erc721Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
|
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -913,7 +913,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721Amount = new BigNumber(1);
|
const erc721Amount = new BigNumber(1);
|
||||||
const amounts = [erc721Amount, erc721Amount];
|
const amounts = [erc721Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
|
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -946,7 +946,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
||||||
const amounts = [erc20Amount, erc721Amount];
|
const amounts = [erc20Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -984,10 +984,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const amounts = [erc20Amount, erc721Amount];
|
const amounts = [erc20Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
||||||
const extraData = '0102030405060708';
|
const extraData = '0102030405060708';
|
||||||
const assetData = `${assetDataInterface.MultiAsset.getABIEncodedTransactionData(
|
const assetData = `${assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`;
|
||||||
amounts,
|
|
||||||
nestedAssetData,
|
|
||||||
)}${extraData}`;
|
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -1024,7 +1021,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
|
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
|
||||||
const amounts = [erc20Amount1, erc20Amount2];
|
const amounts = [erc20Amount1, erc20Amount2];
|
||||||
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
|
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -1085,7 +1082,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
erc721AssetData3,
|
erc721AssetData3,
|
||||||
erc721AssetData4,
|
erc721AssetData4,
|
||||||
];
|
];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -1143,7 +1140,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
||||||
const amounts = [erc20Amount, erc721Amount];
|
const amounts = [erc20Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -1169,6 +1166,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
|
const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
|
||||||
const amounts = [erc20Amount, erc721Amount];
|
const amounts = [erc20Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
|
const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
|
||||||
|
// HACK: This is used to get around validation built into assetDataUtils
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
@ -1192,6 +1190,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
||||||
const amounts = [erc20Amount];
|
const amounts = [erc20Amount];
|
||||||
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
||||||
|
// HACK: This is used to get around validation built into assetDataUtils
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
@ -1214,7 +1213,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
|
||||||
const amounts = [erc20Amount];
|
const amounts = [erc20Amount];
|
||||||
const nestedAssetData = [erc20AssetData];
|
const nestedAssetData = [erc20AssetData];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
@ -1238,6 +1237,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721AssetData = '0x123456';
|
const erc721AssetData = '0x123456';
|
||||||
const amounts = [erc20Amount, erc721Amount];
|
const amounts = [erc20Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
||||||
|
// HACK: This is used to get around validation built into assetDataUtils
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
@ -1262,7 +1262,7 @@ describe('Asset Transfer Proxies', () => {
|
|||||||
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
|
||||||
const amounts = [erc20Amount, erc721Amount];
|
const amounts = [erc20Amount, erc721Amount];
|
||||||
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
const nestedAssetData = [erc20AssetData, erc721AssetData];
|
||||||
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||||
assetData,
|
assetData,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { artifacts as interfacesArtifacts, IAssetDataContract } from '@0x/contracts-interfaces';
|
|
||||||
import {
|
import {
|
||||||
chaiSetup,
|
chaiSetup,
|
||||||
constants,
|
constants,
|
||||||
@ -43,11 +42,6 @@ import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
|||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
const assetDataInterface = new IAssetDataContract(
|
|
||||||
interfacesArtifacts.IAssetData.compilerOutput.abi,
|
|
||||||
constants.NULL_ADDRESS,
|
|
||||||
provider,
|
|
||||||
);
|
|
||||||
// tslint:disable:no-unnecessary-type-assertion
|
// tslint:disable:no-unnecessary-type-assertion
|
||||||
describe('Exchange core', () => {
|
describe('Exchange core', () => {
|
||||||
let makerAddress: string;
|
let makerAddress: string;
|
||||||
@ -777,10 +771,7 @@ describe('Exchange core', () => {
|
|||||||
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
||||||
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
||||||
];
|
];
|
||||||
const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
|
const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
|
||||||
makerAmounts,
|
|
||||||
makerNestedAssetData,
|
|
||||||
);
|
|
||||||
const makerAssetAmount = new BigNumber(1);
|
const makerAssetAmount = new BigNumber(1);
|
||||||
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
const takerAssetAmount = new BigNumber(10);
|
const takerAssetAmount = new BigNumber(10);
|
||||||
@ -830,10 +821,7 @@ describe('Exchange core', () => {
|
|||||||
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
||||||
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
||||||
];
|
];
|
||||||
const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
|
const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
|
||||||
makerAmounts,
|
|
||||||
makerNestedAssetData,
|
|
||||||
);
|
|
||||||
const makerAssetAmount = new BigNumber(1);
|
const makerAssetAmount = new BigNumber(1);
|
||||||
const takerAmounts = [new BigNumber(10), new BigNumber(1)];
|
const takerAmounts = [new BigNumber(10), new BigNumber(1)];
|
||||||
const takerAssetId = erc721TakerAssetIds[0];
|
const takerAssetId = erc721TakerAssetIds[0];
|
||||||
@ -841,10 +829,7 @@ describe('Exchange core', () => {
|
|||||||
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
||||||
assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||||
];
|
];
|
||||||
const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
|
const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
|
||||||
takerAmounts,
|
|
||||||
takerNestedAssetData,
|
|
||||||
);
|
|
||||||
const takerAssetAmount = new BigNumber(1);
|
const takerAssetAmount = new BigNumber(1);
|
||||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||||
makerAssetData,
|
makerAssetData,
|
||||||
@ -900,10 +885,7 @@ describe('Exchange core', () => {
|
|||||||
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
||||||
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
||||||
];
|
];
|
||||||
const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
|
const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
|
||||||
makerAmounts,
|
|
||||||
makerNestedAssetData,
|
|
||||||
);
|
|
||||||
const makerAssetAmount = new BigNumber(30);
|
const makerAssetAmount = new BigNumber(30);
|
||||||
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
const takerAssetAmount = new BigNumber(10);
|
const takerAssetAmount = new BigNumber(10);
|
||||||
@ -980,10 +962,7 @@ describe('Exchange core', () => {
|
|||||||
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
||||||
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
||||||
];
|
];
|
||||||
const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
|
const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
|
||||||
takerAmounts,
|
|
||||||
takerNestedAssetData,
|
|
||||||
);
|
|
||||||
const takerAssetAmount = new BigNumber(30);
|
const takerAssetAmount = new BigNumber(30);
|
||||||
const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
const makerAssetAmount = new BigNumber(10);
|
const makerAssetAmount = new BigNumber(10);
|
||||||
|
@ -22,6 +22,7 @@ import * as UnlimitedAllowanceToken_v1 from '../../generated-artifacts/Unlimited
|
|||||||
import * as WETH9 from '../../generated-artifacts/WETH9.json';
|
import * as WETH9 from '../../generated-artifacts/WETH9.json';
|
||||||
import * as ZRXToken from '../../generated-artifacts/ZRXToken.json';
|
import * as ZRXToken from '../../generated-artifacts/ZRXToken.json';
|
||||||
|
|
||||||
|
// tslint:disable:no-unnecessary-type-assertion
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
DummyERC20Token: DummyERC20Token as ContractArtifact,
|
DummyERC20Token: DummyERC20Token as ContractArtifact,
|
||||||
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
|
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note":
|
||||||
|
"Export `MultiAssetData`, `MultiAssetDataWithRecursiveDecoding`, `ObjectMap`, and `SingleAssetData` from types. No longer export `AssetData`.",
|
||||||
|
"pr": 1363
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.0.8",
|
"version": "2.0.8",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -79,10 +79,13 @@ export {
|
|||||||
OrderStateInvalid,
|
OrderStateInvalid,
|
||||||
OrderState,
|
OrderState,
|
||||||
AssetProxyId,
|
AssetProxyId,
|
||||||
AssetData,
|
SingleAssetData,
|
||||||
ERC20AssetData,
|
ERC20AssetData,
|
||||||
ERC721AssetData,
|
ERC721AssetData,
|
||||||
|
MultiAssetData,
|
||||||
|
MultiAssetDataWithRecursiveDecoding,
|
||||||
SignatureType,
|
SignatureType,
|
||||||
|
ObjectMap,
|
||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
Stats,
|
Stats,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "4.1.4",
|
"version": "4.2.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Add support for Trust Wallet signature denial error"
|
"note": "Add support for Trust Wallet signature denial error"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add balance and allowance queries for `MultiAssetProxy`",
|
||||||
|
"pr": 1363
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// tslint:disable:no-unnecessary-type-assertion
|
|
||||||
import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils';
|
import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils';
|
||||||
import { AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0x/types';
|
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { BlockParamLiteral } from 'ethereum-types';
|
import { BlockParamLiteral } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper';
|
import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper';
|
||||||
import { ERC721TokenWrapper } from '../contract_wrappers/erc721_token_wrapper';
|
import { ERC721TokenWrapper } from '../contract_wrappers/erc721_token_wrapper';
|
||||||
@ -18,42 +17,45 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP
|
|||||||
}
|
}
|
||||||
public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
|
public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
|
||||||
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
|
let balance: BigNumber | undefined;
|
||||||
const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
|
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||||
const balance = await this._erc20Token.getBalanceAsync(decodedERC20AssetData.tokenAddress, userAddress, {
|
balance = await this._erc20Token.getBalanceAsync(decodedAssetData.tokenAddress, userAddress, {
|
||||||
defaultBlock: this._stateLayer,
|
defaultBlock: this._stateLayer,
|
||||||
});
|
});
|
||||||
return balance;
|
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
} else {
|
|
||||||
const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
|
|
||||||
const tokenOwner = await this._erc721Token.getOwnerOfAsync(
|
const tokenOwner = await this._erc721Token.getOwnerOfAsync(
|
||||||
decodedERC721AssetData.tokenAddress,
|
decodedAssetData.tokenAddress,
|
||||||
decodedERC721AssetData.tokenId,
|
decodedAssetData.tokenId,
|
||||||
{
|
{
|
||||||
defaultBlock: this._stateLayer,
|
defaultBlock: this._stateLayer,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
|
balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
|
||||||
return balance;
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
// The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`.
|
||||||
|
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
|
||||||
|
const nestedAmountElement = decodedAssetData.amounts[index];
|
||||||
|
const nestedAssetBalance = (await this.getBalanceAsync(
|
||||||
|
nestedAssetDataElement,
|
||||||
|
userAddress,
|
||||||
|
)).dividedToIntegerBy(nestedAmountElement);
|
||||||
|
if (_.isUndefined(balance) || nestedAssetBalance.lessThan(balance)) {
|
||||||
|
balance = nestedAssetBalance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return balance as BigNumber;
|
||||||
|
}
|
||||||
public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
|
public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
|
||||||
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
|
let proxyAllowance: BigNumber | undefined;
|
||||||
const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
|
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||||
const proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(
|
proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(decodedAssetData.tokenAddress, userAddress, {
|
||||||
decodedERC20AssetData.tokenAddress,
|
|
||||||
userAddress,
|
|
||||||
{
|
|
||||||
defaultBlock: this._stateLayer,
|
defaultBlock: this._stateLayer,
|
||||||
},
|
});
|
||||||
);
|
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
return proxyAllowance;
|
|
||||||
} else {
|
|
||||||
const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
|
|
||||||
|
|
||||||
const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync(
|
const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync(
|
||||||
decodedERC721AssetData.tokenAddress,
|
decodedAssetData.tokenAddress,
|
||||||
userAddress,
|
userAddress,
|
||||||
{
|
{
|
||||||
defaultBlock: this._stateLayer,
|
defaultBlock: this._stateLayer,
|
||||||
@ -63,15 +65,27 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP
|
|||||||
return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
} else {
|
} else {
|
||||||
const isApproved = await this._erc721Token.isProxyApprovedAsync(
|
const isApproved = await this._erc721Token.isProxyApprovedAsync(
|
||||||
decodedERC721AssetData.tokenAddress,
|
decodedAssetData.tokenAddress,
|
||||||
decodedERC721AssetData.tokenId,
|
decodedAssetData.tokenId,
|
||||||
{
|
{
|
||||||
defaultBlock: this._stateLayer,
|
defaultBlock: this._stateLayer,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
|
proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
|
||||||
return proxyAllowance;
|
}
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
// The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`.
|
||||||
|
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
|
||||||
|
const nestedAmountElement = decodedAssetData.amounts[index];
|
||||||
|
const nestedAssetAllowance = (await this.getProxyAllowanceAsync(
|
||||||
|
nestedAssetDataElement,
|
||||||
|
userAddress,
|
||||||
|
)).dividedToIntegerBy(nestedAmountElement);
|
||||||
|
if (_.isUndefined(proxyAllowance) || nestedAssetAllowance.lessThan(proxyAllowance)) {
|
||||||
|
proxyAllowance = nestedAssetAllowance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return proxyAllowance as BigNumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.1.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add support for MultiAssetProxy",
|
||||||
|
"pr": 1363
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.16",
|
"version": "1.0.16",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -2,7 +2,7 @@ import { DummyERC20TokenContract, DummyERC721TokenContract, ExchangeContract } f
|
|||||||
import * as artifacts from '@0x/contract-artifacts';
|
import * as artifacts from '@0x/contract-artifacts';
|
||||||
import { assetDataUtils } from '@0x/order-utils';
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
|
import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
|
||||||
import { AssetProxyId, ERC721AssetData, OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
|
import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { Provider } from 'ethereum-types';
|
import { Provider } from 'ethereum-types';
|
||||||
@ -150,39 +150,8 @@ export class FillScenarios {
|
|||||||
feeRecipientAddress: string,
|
feeRecipientAddress: string,
|
||||||
expirationTimeSeconds?: BigNumber,
|
expirationTimeSeconds?: BigNumber,
|
||||||
): Promise<SignedOrder> {
|
): Promise<SignedOrder> {
|
||||||
const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(makerAssetData);
|
await this._increaseBalanceAndAllowanceWithAssetDataAsync(makerAssetData, makerAddress, makerFillableAmount);
|
||||||
if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
|
await this._increaseBalanceAndAllowanceWithAssetDataAsync(takerAssetData, takerAddress, takerFillableAmount);
|
||||||
await this._increaseERC20BalanceAndAllowanceAsync(
|
|
||||||
decodedMakerAssetData.tokenAddress,
|
|
||||||
makerAddress,
|
|
||||||
makerFillableAmount,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (!makerFillableAmount.equals(1)) {
|
|
||||||
throw new Error(`ERC721 makerFillableAmount should be equal 1. Found: ${makerFillableAmount}`);
|
|
||||||
}
|
|
||||||
await this._increaseERC721BalanceAndAllowanceAsync(
|
|
||||||
decodedMakerAssetData.tokenAddress,
|
|
||||||
makerAddress,
|
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
|
||||||
(decodedMakerAssetData as ERC721AssetData).tokenId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const decodedTakerAssetData = assetDataUtils.decodeAssetDataOrThrow(takerAssetData);
|
|
||||||
if (decodedTakerAssetData.assetProxyId === AssetProxyId.ERC20) {
|
|
||||||
const takerTokenAddress = decodedTakerAssetData.tokenAddress;
|
|
||||||
await this._increaseERC20BalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount);
|
|
||||||
} else {
|
|
||||||
if (!takerFillableAmount.equals(1)) {
|
|
||||||
throw new Error(`ERC721 takerFillableAmount should be equal 1. Found: ${takerFillableAmount}`);
|
|
||||||
}
|
|
||||||
await this._increaseERC721BalanceAndAllowanceAsync(
|
|
||||||
decodedTakerAssetData.tokenAddress,
|
|
||||||
takerAddress,
|
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
|
||||||
(decodedMakerAssetData as ERC721AssetData).tokenId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Fees
|
// Fees
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
|
this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
|
||||||
@ -298,4 +267,30 @@ export class FillScenarios {
|
|||||||
});
|
});
|
||||||
await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
||||||
}
|
}
|
||||||
|
private async _increaseBalanceAndAllowanceWithAssetDataAsync(
|
||||||
|
assetData: string,
|
||||||
|
userAddress: string,
|
||||||
|
amount: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
|
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||||
|
await this._increaseERC20BalanceAndAllowanceAsync(decodedAssetData.tokenAddress, userAddress, amount);
|
||||||
|
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
|
await this._increaseERC721BalanceAndAllowanceAsync(
|
||||||
|
decodedAssetData.tokenAddress,
|
||||||
|
userAddress,
|
||||||
|
decodedAssetData.tokenId,
|
||||||
|
);
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
|
||||||
|
const amountsElement = decodedAssetData.amounts[index];
|
||||||
|
const totalAmount = amount.times(amountsElement);
|
||||||
|
await this._increaseBalanceAndAllowanceWithAssetDataAsync(
|
||||||
|
nestedAssetDataElement,
|
||||||
|
userAddress,
|
||||||
|
totalAmount,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.1.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note":
|
||||||
|
"Use new ABI encoder, add encoding/decoding logic for MultiAsset assetData, and add information to return values in orderStateUtils",
|
||||||
|
"pr": 1363
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "3.0.7",
|
"version": "3.0.7",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
import { AssetData, AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0x/types';
|
import {
|
||||||
import { BigNumber } from '@0x/utils';
|
AssetProxyId,
|
||||||
import ethAbi = require('ethereumjs-abi');
|
ERC20AssetData,
|
||||||
import ethUtil = require('ethereumjs-util');
|
ERC721AssetData,
|
||||||
|
MultiAssetData,
|
||||||
|
MultiAssetDataWithRecursiveDecoding,
|
||||||
|
SingleAssetData,
|
||||||
|
} from '@0x/types';
|
||||||
|
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
|
const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: true };
|
||||||
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
|
|
||||||
export const assetDataUtils = {
|
export const assetDataUtils = {
|
||||||
/**
|
/**
|
||||||
* Encodes an ERC20 token address into a hex encoded assetData string, usable in the makerAssetData or
|
* Encodes an ERC20 token address into a hex encoded assetData string, usable in the makerAssetData or
|
||||||
@ -13,7 +22,10 @@ export const assetDataUtils = {
|
|||||||
* @return The hex encoded assetData string
|
* @return The hex encoded assetData string
|
||||||
*/
|
*/
|
||||||
encodeERC20AssetData(tokenAddress: string): string {
|
encodeERC20AssetData(tokenAddress: string): string {
|
||||||
return ethUtil.bufferToHex(ethAbi.simpleEncode('ERC20Token(address)', tokenAddress));
|
const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
|
||||||
|
const args = [tokenAddress];
|
||||||
|
const assetData = abiEncoder.encode(args, encodingRules);
|
||||||
|
return assetData;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Decodes an ERC20 assetData hex string into it's corresponding ERC20 tokenAddress & assetProxyId
|
* Decodes an ERC20 assetData hex string into it's corresponding ERC20 tokenAddress & assetProxyId
|
||||||
@ -21,26 +33,14 @@ export const assetDataUtils = {
|
|||||||
* @return An object containing the decoded tokenAddress & assetProxyId
|
* @return An object containing the decoded tokenAddress & assetProxyId
|
||||||
*/
|
*/
|
||||||
decodeERC20AssetData(assetData: string): ERC20AssetData {
|
decodeERC20AssetData(assetData: string): ERC20AssetData {
|
||||||
const data = ethUtil.toBuffer(assetData);
|
assetDataUtils.assertIsERC20AssetData(assetData);
|
||||||
if (data.byteLength < constants.ERC20_ASSET_DATA_BYTE_LENGTH) {
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
throw new Error(
|
const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
|
||||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least ${
|
const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
|
||||||
constants.ERC20_ASSET_DATA_BYTE_LENGTH
|
|
||||||
}. Got ${data.byteLength}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const assetProxyId = ethUtil.bufferToHex(data.slice(0, constants.SELECTOR_LENGTH));
|
|
||||||
if (assetProxyId !== AssetProxyId.ERC20) {
|
|
||||||
throw new Error(
|
|
||||||
`Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be ERC20 (${
|
|
||||||
AssetProxyId.ERC20
|
|
||||||
}), but got ${assetProxyId}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const [tokenAddress] = ethAbi.rawDecode(['address'], data.slice(constants.SELECTOR_LENGTH));
|
|
||||||
return {
|
return {
|
||||||
assetProxyId,
|
assetProxyId,
|
||||||
tokenAddress: ethUtil.addHexPrefix(tokenAddress),
|
// TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
|
||||||
|
tokenAddress: (decodedAssetData as any).tokenContract,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -51,14 +51,10 @@ export const assetDataUtils = {
|
|||||||
* @return The hex encoded assetData string
|
* @return The hex encoded assetData string
|
||||||
*/
|
*/
|
||||||
encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
|
encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
|
||||||
// TODO: Pass `tokendId` as a BigNumber.
|
const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
|
||||||
return ethUtil.bufferToHex(
|
const args = [tokenAddress, tokenId];
|
||||||
ethAbi.simpleEncode(
|
const assetData = abiEncoder.encode(args, encodingRules);
|
||||||
'ERC721Token(address,uint256)',
|
return assetData;
|
||||||
tokenAddress,
|
|
||||||
`0x${tokenId.toString(constants.BASE_16)}`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Decodes an ERC721 assetData hex string into it's corresponding ERC721 tokenAddress, tokenId & assetProxyId
|
* Decodes an ERC721 assetData hex string into it's corresponding ERC721 tokenAddress, tokenId & assetProxyId
|
||||||
@ -66,27 +62,99 @@ export const assetDataUtils = {
|
|||||||
* @return An object containing the decoded tokenAddress, tokenId & assetProxyId
|
* @return An object containing the decoded tokenAddress, tokenId & assetProxyId
|
||||||
*/
|
*/
|
||||||
decodeERC721AssetData(assetData: string): ERC721AssetData {
|
decodeERC721AssetData(assetData: string): ERC721AssetData {
|
||||||
const data = ethUtil.toBuffer(assetData);
|
assetDataUtils.assertIsERC721AssetData(assetData);
|
||||||
if (data.byteLength < constants.ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH) {
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
throw new Error(
|
const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
|
||||||
`Could not decode ERC721 Asset Data. Expected length of encoded data to be at least ${
|
const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
|
||||||
constants.ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH
|
|
||||||
}. Got ${data.byteLength}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const assetProxyId = ethUtil.bufferToHex(data.slice(0, constants.SELECTOR_LENGTH));
|
|
||||||
if (assetProxyId !== AssetProxyId.ERC721) {
|
|
||||||
throw new Error(
|
|
||||||
`Could not decode ERC721 Asset Data. Expected Asset Proxy Id to be ERC721 (${
|
|
||||||
AssetProxyId.ERC721
|
|
||||||
}), but got ${assetProxyId}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const [tokenAddress, tokenId] = ethAbi.rawDecode(['address', 'uint256'], data.slice(constants.SELECTOR_LENGTH));
|
|
||||||
return {
|
return {
|
||||||
assetProxyId,
|
assetProxyId,
|
||||||
tokenAddress: ethUtil.addHexPrefix(tokenAddress),
|
// TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
|
||||||
tokenId: new BigNumber(tokenId.toString()),
|
tokenAddress: (decodedAssetData as any).tokenContract,
|
||||||
|
tokenId: (decodedAssetData as any).tokenId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or
|
||||||
|
* takerAssetData fields in a 0x order.
|
||||||
|
* @param amounts Amounts of each asset that correspond to a single unit within an order.
|
||||||
|
* @param nestedAssetData assetData strings that correspond to a valid assetProxyId.
|
||||||
|
* @return The hex encoded assetData string
|
||||||
|
*/
|
||||||
|
encodeMultiAssetData(amounts: BigNumber[], nestedAssetData: string[]): string {
|
||||||
|
if (amounts.length !== nestedAssetData.length) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid MultiAsset arguments. Expected length of 'amounts' (${
|
||||||
|
amounts.length
|
||||||
|
}) to equal length of 'nestedAssetData' (${nestedAssetData.length})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_.forEach(nestedAssetData, assetDataElement => assetDataUtils.validateAssetDataOrThrow(assetDataElement));
|
||||||
|
const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
|
||||||
|
const args = [amounts, nestedAssetData];
|
||||||
|
const assetData = abiEncoder.encode(args, encodingRules);
|
||||||
|
return assetData;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Decodes a MultiAsset assetData hex string into it's corresponding amounts and nestedAssetData
|
||||||
|
* @param assetData Hex encoded assetData string to decode
|
||||||
|
* @return An object containing the decoded amounts and nestedAssetData
|
||||||
|
*/
|
||||||
|
decodeMultiAssetData(assetData: string): MultiAssetData {
|
||||||
|
assetDataUtils.assertIsMultiAssetData(assetData);
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
|
||||||
|
const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
|
||||||
|
// TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
|
||||||
|
const amounts = (decodedAssetData as any).amounts;
|
||||||
|
const nestedAssetData = (decodedAssetData as any).nestedAssetData;
|
||||||
|
if (amounts.length !== nestedAssetData.length) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid MultiAsset assetData. Expected length of 'amounts' (${
|
||||||
|
amounts.length
|
||||||
|
}) to equal length of 'nestedAssetData' (${nestedAssetData.length})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
assetProxyId,
|
||||||
|
amounts,
|
||||||
|
nestedAssetData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Decodes a MultiAsset assetData hex string into it's corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened)
|
||||||
|
* @param assetData Hex encoded assetData string to decode
|
||||||
|
* @return An object containing the decoded amounts and nestedAssetData
|
||||||
|
*/
|
||||||
|
decodeMultiAssetDataRecursively(assetData: string): MultiAssetDataWithRecursiveDecoding {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||||
|
const amounts: any[] = [];
|
||||||
|
const decodedNestedAssetData = _.map(
|
||||||
|
decodedAssetData.nestedAssetData as string[],
|
||||||
|
(nestedAssetDataElement, index) => {
|
||||||
|
const decodedNestedAssetDataElement = assetDataUtils.decodeAssetDataOrThrow(nestedAssetDataElement);
|
||||||
|
if (decodedNestedAssetDataElement.assetProxyId === AssetProxyId.MultiAsset) {
|
||||||
|
const recursivelyDecodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(
|
||||||
|
nestedAssetDataElement,
|
||||||
|
);
|
||||||
|
amounts.push(
|
||||||
|
_.map(recursivelyDecodedAssetData.amounts, amountElement =>
|
||||||
|
amountElement.times(decodedAssetData.amounts[index]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return recursivelyDecodedAssetData.nestedAssetData;
|
||||||
|
} else {
|
||||||
|
amounts.push(decodedAssetData.amounts[index]);
|
||||||
|
return decodedNestedAssetDataElement as SingleAssetData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const flattenedAmounts = _.flattenDeep(amounts);
|
||||||
|
const flattenedDecodedNestedAssetData = _.flattenDeep(decodedNestedAssetData);
|
||||||
|
return {
|
||||||
|
assetProxyId: decodedAssetData.assetProxyId,
|
||||||
|
amounts: flattenedAmounts,
|
||||||
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
nestedAssetData: flattenedDecodedNestedAssetData as SingleAssetData[],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -95,24 +163,133 @@ export const assetDataUtils = {
|
|||||||
* @return The assetProxyId
|
* @return The assetProxyId
|
||||||
*/
|
*/
|
||||||
decodeAssetProxyId(assetData: string): AssetProxyId {
|
decodeAssetProxyId(assetData: string): AssetProxyId {
|
||||||
const encodedAssetData = ethUtil.toBuffer(assetData);
|
if (assetData.length < constants.SELECTOR_CHAR_LENGTH_WITH_PREFIX) {
|
||||||
if (encodedAssetData.byteLength < constants.SELECTOR_LENGTH) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not decode assetData. Expected length of encoded data to be at least 4. Got ${
|
`Could not decode assetData. Expected length of encoded data to be at least 10. Got ${
|
||||||
encodedAssetData.byteLength
|
assetData.length
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const encodedAssetProxyId = encodedAssetData.slice(0, constants.SELECTOR_LENGTH);
|
const assetProxyId = assetData.slice(0, constants.SELECTOR_CHAR_LENGTH_WITH_PREFIX);
|
||||||
const assetProxyId = decodeAssetProxyId(encodedAssetProxyId);
|
if (
|
||||||
|
assetProxyId !== AssetProxyId.ERC20 &&
|
||||||
|
assetProxyId !== AssetProxyId.ERC721 &&
|
||||||
|
assetProxyId !== AssetProxyId.MultiAsset
|
||||||
|
) {
|
||||||
|
throw new Error(`Invalid assetProxyId: ${assetProxyId}`);
|
||||||
|
}
|
||||||
return assetProxyId;
|
return assetProxyId;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Checks if the decoded asset data is valid ERC20 data
|
||||||
|
* @param decodedAssetData The decoded asset data to check
|
||||||
|
*/
|
||||||
|
isERC20AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC20AssetData {
|
||||||
|
return decodedAssetData.assetProxyId === AssetProxyId.ERC20;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Checks if the decoded asset data is valid ERC721 data
|
||||||
|
* @param decodedAssetData The decoded asset data to check
|
||||||
|
*/
|
||||||
|
isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC721AssetData {
|
||||||
|
return decodedAssetData.assetProxyId === AssetProxyId.ERC721;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Checks if the decoded asset data is valid MultiAsset data
|
||||||
|
* @param decodedAssetData The decoded asset data to check
|
||||||
|
*/
|
||||||
|
isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData {
|
||||||
|
return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Throws if the length or assetProxyId are invalid for the ERC20Proxy.
|
||||||
|
* @param assetData Hex encoded assetData string
|
||||||
|
*/
|
||||||
|
assertIsERC20AssetData(assetData: string): void {
|
||||||
|
if (assetData.length < constants.ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least ${
|
||||||
|
constants.ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
|
||||||
|
}. Got ${assetData.length}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
if (assetProxyId !== AssetProxyId.ERC20) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not decode ERC20 assetData. Expected assetProxyId to be ERC20 (${
|
||||||
|
AssetProxyId.ERC20
|
||||||
|
}), but got ${assetProxyId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Throws if the length or assetProxyId are invalid for the ERC721Proxy.
|
||||||
|
* @param assetData Hex encoded assetData string
|
||||||
|
*/
|
||||||
|
assertIsERC721AssetData(assetData: string): void {
|
||||||
|
if (assetData.length < constants.ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not decode ERC721 assetData. Expected length of encoded data to be at least ${
|
||||||
|
constants.ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
|
||||||
|
}. Got ${assetData.length}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
if (assetProxyId !== AssetProxyId.ERC721) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not decode ERC721 assetData. Expected assetProxyId to be ERC721 (${
|
||||||
|
AssetProxyId.ERC721
|
||||||
|
}), but got ${assetProxyId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Throws if the length or assetProxyId are invalid for the MultiAssetProxy.
|
||||||
|
* @param assetData Hex encoded assetData string
|
||||||
|
*/
|
||||||
|
assertIsMultiAssetData(assetData: string): void {
|
||||||
|
if (assetData.length < constants.MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not decode MultiAsset assetData. Expected length of encoded data to be at least ${
|
||||||
|
constants.MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
|
||||||
|
}. Got ${assetData.length}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
if (assetProxyId !== AssetProxyId.MultiAsset) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not decode MultiAsset assetData. Expected assetProxyId to be MultiAsset (${
|
||||||
|
AssetProxyId.MultiAsset
|
||||||
|
}), but got ${assetProxyId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Throws if the length or assetProxyId are invalid for the corresponding AssetProxy.
|
||||||
|
* @param assetData Hex encoded assetData string
|
||||||
|
*/
|
||||||
|
validateAssetDataOrThrow(assetData: string): void {
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
switch (assetProxyId) {
|
||||||
|
case AssetProxyId.ERC20:
|
||||||
|
assetDataUtils.assertIsERC20AssetData(assetData);
|
||||||
|
break;
|
||||||
|
case AssetProxyId.ERC721:
|
||||||
|
assetDataUtils.assertIsERC721AssetData(assetData);
|
||||||
|
break;
|
||||||
|
case AssetProxyId.MultiAsset:
|
||||||
|
assetDataUtils.assertIsMultiAssetData(assetData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Decode any assetData into it's corresponding assetData object
|
* Decode any assetData into it's corresponding assetData object
|
||||||
* @param assetData Hex encoded assetData string to decode
|
* @param assetData Hex encoded assetData string to decode
|
||||||
* @return Either a ERC20 or ERC721 assetData object
|
* @return Either a ERC20 or ERC721 assetData object
|
||||||
*/
|
*/
|
||||||
decodeAssetDataOrThrow(assetData: string): AssetData {
|
decodeAssetDataOrThrow(assetData: string): SingleAssetData | MultiAssetData {
|
||||||
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
switch (assetProxyId) {
|
switch (assetProxyId) {
|
||||||
case AssetProxyId.ERC20:
|
case AssetProxyId.ERC20:
|
||||||
@ -121,19 +298,11 @@ export const assetDataUtils = {
|
|||||||
case AssetProxyId.ERC721:
|
case AssetProxyId.ERC721:
|
||||||
const erc721AssetData = assetDataUtils.decodeERC721AssetData(assetData);
|
const erc721AssetData = assetDataUtils.decodeERC721AssetData(assetData);
|
||||||
return erc721AssetData;
|
return erc721AssetData;
|
||||||
|
case AssetProxyId.MultiAsset:
|
||||||
|
const multiAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||||
|
return multiAssetData;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
|
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function decodeAssetProxyId(encodedAssetProxyId: Buffer): AssetProxyId {
|
|
||||||
const hexString = ethUtil.bufferToHex(encodedAssetProxyId);
|
|
||||||
if (hexString === AssetProxyId.ERC20) {
|
|
||||||
return AssetProxyId.ERC20;
|
|
||||||
}
|
|
||||||
if (hexString === AssetProxyId.ERC721) {
|
|
||||||
return AssetProxyId.ERC721;
|
|
||||||
}
|
|
||||||
throw new Error(`Invalid ProxyId: ${hexString}`);
|
|
||||||
}
|
|
||||||
|
@ -1,16 +1,71 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { MethodAbi } from 'ethereum-types';
|
||||||
|
|
||||||
|
const ERC20_METHOD_ABI: MethodAbi = {
|
||||||
|
constant: false,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: 'tokenContract',
|
||||||
|
type: 'address',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'ERC20Token',
|
||||||
|
outputs: [],
|
||||||
|
payable: false,
|
||||||
|
stateMutability: 'nonpayable',
|
||||||
|
type: 'function',
|
||||||
|
};
|
||||||
|
|
||||||
|
const ERC721_METHOD_ABI: MethodAbi = {
|
||||||
|
constant: false,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: 'tokenContract',
|
||||||
|
type: 'address',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tokenId',
|
||||||
|
type: 'uint256',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'ERC721Token',
|
||||||
|
outputs: [],
|
||||||
|
payable: false,
|
||||||
|
stateMutability: 'nonpayable',
|
||||||
|
type: 'function',
|
||||||
|
};
|
||||||
|
|
||||||
|
const MULTI_ASSET_METHOD_ABI: MethodAbi = {
|
||||||
|
constant: false,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: 'amounts',
|
||||||
|
type: 'uint256[]',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nestedAssetData',
|
||||||
|
type: 'bytes[]',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'MultiAsset',
|
||||||
|
outputs: [],
|
||||||
|
payable: false,
|
||||||
|
stateMutability: 'nonpayable',
|
||||||
|
type: 'function',
|
||||||
|
};
|
||||||
|
|
||||||
export const constants = {
|
export const constants = {
|
||||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||||
NULL_BYTES: '0x',
|
NULL_BYTES: '0x',
|
||||||
|
NULL_ERC20_ASSET_DATA: '0xf47261b00000000000000000000000000000000000000000000000000000000000000000',
|
||||||
// tslint:disable-next-line:custom-no-magic-numbers
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
|
||||||
TESTRPC_NETWORK_ID: 50,
|
TESTRPC_NETWORK_ID: 50,
|
||||||
ADDRESS_LENGTH: 20,
|
ADDRESS_LENGTH: 20,
|
||||||
ERC20_ASSET_DATA_BYTE_LENGTH: 36,
|
ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 74,
|
||||||
ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH: 53,
|
ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 136,
|
||||||
SELECTOR_LENGTH: 4,
|
MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 266,
|
||||||
BASE_16: 16,
|
SELECTOR_CHAR_LENGTH_WITH_PREFIX: 10,
|
||||||
INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite
|
INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite
|
||||||
ZERO_AMOUNT: new BigNumber(0),
|
ZERO_AMOUNT: new BigNumber(0),
|
||||||
EIP712_DOMAIN_NAME: '0x Protocol',
|
EIP712_DOMAIN_NAME: '0x Protocol',
|
||||||
@ -48,4 +103,7 @@ export const constants = {
|
|||||||
{ name: 'data', type: 'bytes' },
|
{ name: 'data', type: 'bytes' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
ERC20_METHOD_ABI,
|
||||||
|
ERC721_METHOD_ABI,
|
||||||
|
MULTI_ASSET_METHOD_ABI,
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { ExchangeContractErrs } from '@0x/types';
|
import { AssetProxyId, ExchangeContractErrs } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||||
|
import { assetDataUtils } from './asset_data_utils';
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
import { TradeSide, TransferType } from './types';
|
import { TradeSide, TransferType } from './types';
|
||||||
|
|
||||||
@ -74,6 +75,10 @@ export class ExchangeTransferSimulator {
|
|||||||
tradeSide: TradeSide,
|
tradeSide: TradeSide,
|
||||||
transferType: TransferType,
|
transferType: TransferType,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
switch (assetProxyId) {
|
||||||
|
case AssetProxyId.ERC20:
|
||||||
|
case AssetProxyId.ERC721:
|
||||||
// HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
|
// 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
|
// 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.
|
// might be relying on those funds to fill subsequent orders or pay the order's fees.
|
||||||
@ -84,7 +89,11 @@ export class ExchangeTransferSimulator {
|
|||||||
const balance = await this._store.getBalanceAsync(assetData, from);
|
const balance = await this._store.getBalanceAsync(assetData, from);
|
||||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
|
||||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||||
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
ExchangeTransferSimulator._throwValidationError(
|
||||||
|
FailureReason.ProxyAllowance,
|
||||||
|
tradeSide,
|
||||||
|
transferType,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (balance.lessThan(amountInBaseUnits)) {
|
if (balance.lessThan(amountInBaseUnits)) {
|
||||||
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||||
@ -92,6 +101,25 @@ export class ExchangeTransferSimulator {
|
|||||||
await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
|
await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
|
||||||
await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
|
await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
|
||||||
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
|
await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
|
||||||
|
break;
|
||||||
|
case AssetProxyId.MultiAsset:
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||||
|
for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
|
||||||
|
const amountsElement = decodedAssetData.amounts[index];
|
||||||
|
const totalAmount = amountInBaseUnits.times(amountsElement);
|
||||||
|
await this.transferFromAsync(
|
||||||
|
nestedAssetDataElement,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
totalAmount,
|
||||||
|
tradeSide,
|
||||||
|
transferType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private async _decreaseProxyAllowanceAsync(
|
private async _decreaseProxyAllowanceAsync(
|
||||||
assetData: string,
|
assetData: string,
|
||||||
|
@ -34,11 +34,14 @@ export {
|
|||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
OrderState,
|
OrderState,
|
||||||
ECSignature,
|
ECSignature,
|
||||||
AssetData,
|
SingleAssetData,
|
||||||
ERC20AssetData,
|
ERC20AssetData,
|
||||||
ERC721AssetData,
|
ERC721AssetData,
|
||||||
|
MultiAssetData,
|
||||||
|
MultiAssetDataWithRecursiveDecoding,
|
||||||
AssetProxyId,
|
AssetProxyId,
|
||||||
SignatureType,
|
SignatureType,
|
||||||
|
ObjectMap,
|
||||||
OrderStateValid,
|
OrderStateValid,
|
||||||
OrderStateInvalid,
|
OrderStateInvalid,
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
|
ObjectMap,
|
||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
OrderState,
|
OrderState,
|
||||||
OrderStateInvalid,
|
OrderStateInvalid,
|
||||||
@ -7,9 +8,11 @@ import {
|
|||||||
SignedOrder,
|
SignedOrder,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
||||||
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
||||||
|
import { assetDataUtils } from './asset_data_utils';
|
||||||
import { orderHashUtils } from './order_hash';
|
import { orderHashUtils } from './order_hash';
|
||||||
import { OrderValidationUtils } from './order_validation_utils';
|
import { OrderValidationUtils } from './order_validation_utils';
|
||||||
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
||||||
@ -18,7 +21,9 @@ import { utils } from './utils';
|
|||||||
interface SidedOrderRelevantState {
|
interface SidedOrderRelevantState {
|
||||||
isMakerSide: boolean;
|
isMakerSide: boolean;
|
||||||
traderBalance: BigNumber;
|
traderBalance: BigNumber;
|
||||||
|
traderIndividualBalances: ObjectMap<BigNumber>;
|
||||||
traderProxyAllowance: BigNumber;
|
traderProxyAllowance: BigNumber;
|
||||||
|
traderIndividualProxyAllowances: ObjectMap<BigNumber>;
|
||||||
traderFeeBalance: BigNumber;
|
traderFeeBalance: BigNumber;
|
||||||
traderFeeProxyAllowance: BigNumber;
|
traderFeeProxyAllowance: BigNumber;
|
||||||
filledTakerAssetAmount: BigNumber;
|
filledTakerAssetAmount: BigNumber;
|
||||||
@ -121,7 +126,9 @@ export class OrderStateUtils {
|
|||||||
const sidedOrderRelevantState = {
|
const sidedOrderRelevantState = {
|
||||||
isMakerSide: true,
|
isMakerSide: true,
|
||||||
traderBalance: orderRelevantState.makerBalance,
|
traderBalance: orderRelevantState.makerBalance,
|
||||||
|
traderIndividualBalances: orderRelevantState.makerIndividualBalances,
|
||||||
traderProxyAllowance: orderRelevantState.makerProxyAllowance,
|
traderProxyAllowance: orderRelevantState.makerProxyAllowance,
|
||||||
|
traderIndividualProxyAllowances: orderRelevantState.makerIndividualProxyAllowances,
|
||||||
traderFeeBalance: orderRelevantState.makerFeeBalance,
|
traderFeeBalance: orderRelevantState.makerFeeBalance,
|
||||||
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
|
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
|
||||||
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
|
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
|
||||||
@ -165,7 +172,9 @@ export class OrderStateUtils {
|
|||||||
|
|
||||||
const orderRelevantState = {
|
const orderRelevantState = {
|
||||||
makerBalance: sidedOrderRelevantState.traderBalance,
|
makerBalance: sidedOrderRelevantState.traderBalance,
|
||||||
|
makerIndividualBalances: sidedOrderRelevantState.traderIndividualBalances,
|
||||||
makerProxyAllowance: sidedOrderRelevantState.traderProxyAllowance,
|
makerProxyAllowance: sidedOrderRelevantState.traderProxyAllowance,
|
||||||
|
makerIndividualProxyAllowances: sidedOrderRelevantState.traderIndividualProxyAllowances,
|
||||||
makerFeeBalance: sidedOrderRelevantState.traderFeeBalance,
|
makerFeeBalance: sidedOrderRelevantState.traderFeeBalance,
|
||||||
makerFeeProxyAllowance: sidedOrderRelevantState.traderFeeProxyAllowance,
|
makerFeeProxyAllowance: sidedOrderRelevantState.traderFeeProxyAllowance,
|
||||||
filledTakerAssetAmount: sidedOrderRelevantState.filledTakerAssetAmount,
|
filledTakerAssetAmount: sidedOrderRelevantState.filledTakerAssetAmount,
|
||||||
@ -236,10 +245,12 @@ export class OrderStateUtils {
|
|||||||
const isAssetZRX = assetData === zrxAssetData;
|
const isAssetZRX = assetData === zrxAssetData;
|
||||||
|
|
||||||
const traderBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
|
const traderBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
|
||||||
|
const traderIndividualBalances = await this._getAssetBalancesAsync(assetData, traderAddress);
|
||||||
const traderProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
const traderProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
||||||
assetData,
|
assetData,
|
||||||
traderAddress,
|
traderAddress,
|
||||||
);
|
);
|
||||||
|
const traderIndividualProxyAllowances = await this._getAssetProxyAllowancesAsync(assetData, traderAddress);
|
||||||
const traderFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
const traderFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
||||||
zrxAssetData,
|
zrxAssetData,
|
||||||
traderAddress,
|
traderAddress,
|
||||||
@ -278,7 +289,9 @@ export class OrderStateUtils {
|
|||||||
const sidedOrderRelevantState = {
|
const sidedOrderRelevantState = {
|
||||||
isMakerSide,
|
isMakerSide,
|
||||||
traderBalance,
|
traderBalance,
|
||||||
|
traderIndividualBalances,
|
||||||
traderProxyAllowance,
|
traderProxyAllowance,
|
||||||
|
traderIndividualProxyAllowances,
|
||||||
traderFeeBalance,
|
traderFeeBalance,
|
||||||
traderFeeProxyAllowance,
|
traderFeeProxyAllowance,
|
||||||
filledTakerAssetAmount,
|
filledTakerAssetAmount,
|
||||||
@ -287,4 +300,47 @@ export class OrderStateUtils {
|
|||||||
};
|
};
|
||||||
return sidedOrderRelevantState;
|
return sidedOrderRelevantState;
|
||||||
}
|
}
|
||||||
|
private async _getAssetBalancesAsync(
|
||||||
|
assetData: string,
|
||||||
|
traderAddress: string,
|
||||||
|
initialBalances: ObjectMap<BigNumber> = {},
|
||||||
|
): Promise<ObjectMap<BigNumber>> {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
|
let balances: ObjectMap<BigNumber> = { ...initialBalances };
|
||||||
|
if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
|
const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
|
||||||
|
const tokenAddress = decodedAssetData.tokenAddress;
|
||||||
|
balances[tokenAddress] = _.isUndefined(initialBalances[tokenAddress])
|
||||||
|
? balance
|
||||||
|
: balances[tokenAddress].add(balance);
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
for (const assetDataElement of decodedAssetData.nestedAssetData) {
|
||||||
|
balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return balances;
|
||||||
|
}
|
||||||
|
private async _getAssetProxyAllowancesAsync(
|
||||||
|
assetData: string,
|
||||||
|
traderAddress: string,
|
||||||
|
initialAllowances: ObjectMap<BigNumber> = {},
|
||||||
|
): Promise<ObjectMap<BigNumber>> {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
|
let allowances: ObjectMap<BigNumber> = { ...initialAllowances };
|
||||||
|
if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
|
const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
||||||
|
assetData,
|
||||||
|
traderAddress,
|
||||||
|
);
|
||||||
|
const tokenAddress = decodedAssetData.tokenAddress;
|
||||||
|
allowances[tokenAddress] = _.isUndefined(initialAllowances[tokenAddress])
|
||||||
|
? allowance
|
||||||
|
: allowances[tokenAddress].add(allowance);
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
for (const assetDataElement of decodedAssetData.nestedAssetData) {
|
||||||
|
allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allowances;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
|
|||||||
public deleteAllERC721ProxyAllowance(tokenAddress: string, userAddress: string): void {
|
public deleteAllERC721ProxyAllowance(tokenAddress: string, userAddress: string): void {
|
||||||
for (const assetData in this._proxyAllowance) {
|
for (const assetData in this._proxyAllowance) {
|
||||||
if (this._proxyAllowance.hasOwnProperty(assetData)) {
|
if (this._proxyAllowance.hasOwnProperty(assetData)) {
|
||||||
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
const decodedAssetData = assetDataUtils.decodeERC721AssetData(assetData);
|
||||||
if (
|
if (
|
||||||
decodedAssetData.assetProxyId === AssetProxyId.ERC721 &&
|
decodedAssetData.assetProxyId === AssetProxyId.ERC721 &&
|
||||||
decodedAssetData.tokenAddress === tokenAddress &&
|
decodedAssetData.tokenAddress === tokenAddress &&
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
|
||||||
import { ERC20AssetData, ERC721AssetData } from '@0x/types';
|
import { AssetProxyId, ERC721AssetData } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
import { assetDataUtils } from '../src/asset_data_utils';
|
import { assetDataUtils } from '../src/asset_data_utils';
|
||||||
@ -10,41 +10,101 @@ import { chaiSetup } from './utils/chai_setup';
|
|||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
const KNOWN_ENCODINGS = [
|
const KNOWN_ERC20_ENCODING = {
|
||||||
{
|
|
||||||
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
|
assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
},
|
};
|
||||||
{
|
const KNOWN_ERC721_ENCODING = {
|
||||||
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||||
tokenId: new BigNumber(1),
|
tokenId: new BigNumber(1),
|
||||||
assetData:
|
assetData:
|
||||||
'0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
|
'0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
|
||||||
},
|
};
|
||||||
];
|
const KNOWN_MULTI_ASSET_ENCODING = {
|
||||||
|
amounts: [new BigNumber(1), new BigNumber(1)],
|
||||||
const ERC20_ASSET_PROXY_ID = '0xf47261b0';
|
nestedAssetData: [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData],
|
||||||
const ERC721_ASSET_PROXY_ID = '0x02571792';
|
assetData:
|
||||||
|
'0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
|
||||||
|
};
|
||||||
|
|
||||||
describe('assetDataUtils', () => {
|
describe('assetDataUtils', () => {
|
||||||
it('should encode ERC20', () => {
|
it('should encode ERC20', () => {
|
||||||
const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ENCODINGS[0].address);
|
const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address);
|
||||||
expect(assetData).to.equal(KNOWN_ENCODINGS[0].assetData);
|
expect(assetData).to.equal(KNOWN_ERC20_ENCODING.assetData);
|
||||||
});
|
});
|
||||||
it('should decode ERC20', () => {
|
it('should decode ERC20', () => {
|
||||||
const assetData: ERC20AssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ENCODINGS[0].assetData);
|
const decodedAssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData);
|
||||||
expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[0].address);
|
expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
|
||||||
expect(assetData.assetProxyId).to.equal(ERC20_ASSET_PROXY_ID);
|
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
|
||||||
});
|
});
|
||||||
it('should encode ERC721', () => {
|
it('should encode ERC721', () => {
|
||||||
const assetData = assetDataUtils.encodeERC721AssetData(KNOWN_ENCODINGS[1].address, KNOWN_ENCODINGS[1]
|
const assetData = assetDataUtils.encodeERC721AssetData(
|
||||||
.tokenId as BigNumber);
|
KNOWN_ERC721_ENCODING.address,
|
||||||
expect(assetData).to.equal(KNOWN_ENCODINGS[1].assetData);
|
KNOWN_ERC721_ENCODING.tokenId,
|
||||||
|
);
|
||||||
|
expect(assetData).to.equal(KNOWN_ERC721_ENCODING.assetData);
|
||||||
});
|
});
|
||||||
it('should decode ERC721', () => {
|
it('should decode ERC721', () => {
|
||||||
const assetData: ERC721AssetData = assetDataUtils.decodeERC721AssetData(KNOWN_ENCODINGS[1].assetData);
|
const decodedAssetData = assetDataUtils.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData);
|
||||||
expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[1].address);
|
expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
|
||||||
expect(assetData.assetProxyId).to.equal(ERC721_ASSET_PROXY_ID);
|
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
|
||||||
expect(assetData.tokenId).to.be.bignumber.equal(KNOWN_ENCODINGS[1].tokenId);
|
expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
|
||||||
|
});
|
||||||
|
it('should encode ERC20 and ERC721 multiAssetData', () => {
|
||||||
|
const assetData = assetDataUtils.encodeMultiAssetData(
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.amounts,
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
|
||||||
|
);
|
||||||
|
expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
|
||||||
|
});
|
||||||
|
it('should decode ERC20 and ERC721 multiAssetData', () => {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData);
|
||||||
|
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
|
||||||
|
expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
|
||||||
|
expect(decodedAssetData.nestedAssetData).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.nestedAssetData);
|
||||||
|
});
|
||||||
|
it('should recursively decode ERC20 and ERC721 multiAssetData', () => {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(KNOWN_MULTI_ASSET_ENCODING.assetData);
|
||||||
|
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
|
||||||
|
expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
|
||||||
|
const decodedErc20AssetData = decodedAssetData.nestedAssetData[0];
|
||||||
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
const decodedErc721AssetData = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
|
||||||
|
expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
|
||||||
|
expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
|
||||||
|
expect(decodedErc721AssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
|
||||||
|
expect(decodedErc721AssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
|
||||||
|
expect(decodedErc721AssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
|
||||||
|
});
|
||||||
|
it('should recursively decode nested assetData within multiAssetData', () => {
|
||||||
|
const amounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2)];
|
||||||
|
const nestedAssetData = [
|
||||||
|
KNOWN_ERC20_ENCODING.assetData,
|
||||||
|
KNOWN_ERC721_ENCODING.assetData,
|
||||||
|
KNOWN_MULTI_ASSET_ENCODING.assetData,
|
||||||
|
];
|
||||||
|
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(assetData);
|
||||||
|
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
|
||||||
|
const expectedAmounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2), new BigNumber(2)];
|
||||||
|
expect(decodedAssetData.amounts).to.deep.equal(expectedAmounts);
|
||||||
|
const expectedLength = 4;
|
||||||
|
expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedLength);
|
||||||
|
const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[0];
|
||||||
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
|
||||||
|
const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[2];
|
||||||
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
const decodedErc721AssetData2 = decodedAssetData.nestedAssetData[3] as ERC721AssetData;
|
||||||
|
expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
|
||||||
|
expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20);
|
||||||
|
expect(decodedErc721AssetData1.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
|
||||||
|
expect(decodedErc721AssetData1.assetProxyId).to.equal(AssetProxyId.ERC721);
|
||||||
|
expect(decodedErc721AssetData1.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
|
||||||
|
expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
|
||||||
|
expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20);
|
||||||
|
expect(decodedErc721AssetData2.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
|
||||||
|
expect(decodedErc721AssetData2.assetProxyId).to.equal(AssetProxyId.ERC721);
|
||||||
|
expect(decodedErc721AssetData2.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,9 +7,9 @@ import { orderFactory } from '../../src/order_factory';
|
|||||||
const BASE_TEST_ORDER: Order = orderFactory.createOrder(
|
const BASE_TEST_ORDER: Order = orderFactory.createOrder(
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ADDRESS,
|
||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ERC20_ASSET_DATA,
|
||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ERC20_ASSET_DATA,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ADDRESS,
|
||||||
);
|
);
|
||||||
const BASE_TEST_SIGNED_ORDER: SignedOrder = {
|
const BASE_TEST_SIGNED_ORDER: SignedOrder = {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.4.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add support for `MultiAssetProxy`",
|
||||||
|
"pr": 1363
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -7,6 +7,7 @@ export {
|
|||||||
OrderStateInvalid,
|
OrderStateInvalid,
|
||||||
OrderState,
|
OrderState,
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
|
ObjectMap,
|
||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
Stats,
|
Stats,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// tslint:disable:no-unnecessary-type-assertion
|
|
||||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||||
import { AssetProxyId, ERC20AssetData, ERC721AssetData, SignedOrder } from '@0x/types';
|
import { AssetProxyId, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
@ -62,35 +61,18 @@ export class DependentOrderHashesTracker {
|
|||||||
return dependentOrderHashes;
|
return dependentOrderHashes;
|
||||||
}
|
}
|
||||||
public addToDependentOrderHashes(signedOrder: SignedOrder): void {
|
public addToDependentOrderHashes(signedOrder: SignedOrder): void {
|
||||||
const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
|
this._addAssetDataToDependentOrderHashes(signedOrder, signedOrder.makerAssetData);
|
||||||
if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
|
|
||||||
this._addToERC20DependentOrderHashes(signedOrder, (decodedMakerAssetData as ERC20AssetData).tokenAddress);
|
|
||||||
} else {
|
|
||||||
this._addToERC721DependentOrderHashes(
|
|
||||||
signedOrder,
|
|
||||||
(decodedMakerAssetData as ERC721AssetData).tokenAddress,
|
|
||||||
(decodedMakerAssetData as ERC721AssetData).tokenId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this._addToERC20DependentOrderHashes(signedOrder, this._zrxTokenAddress);
|
this._addToERC20DependentOrderHashes(signedOrder, this._zrxTokenAddress);
|
||||||
this._addToMakerDependentOrderHashes(signedOrder);
|
this._addToMakerDependentOrderHashes(signedOrder);
|
||||||
}
|
}
|
||||||
public removeFromDependentOrderHashes(signedOrder: SignedOrder): void {
|
public removeFromDependentOrderHashes(signedOrder: SignedOrder): void {
|
||||||
const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
|
this._removeAssetDataFromDependentOrderHashes(signedOrder, signedOrder.makerAssetData);
|
||||||
if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
|
|
||||||
this._removeFromERC20DependentOrderhashes(
|
|
||||||
signedOrder,
|
|
||||||
(decodedMakerAssetData as ERC20AssetData).tokenAddress,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this._removeFromERC721DependentOrderhashes(
|
|
||||||
signedOrder,
|
|
||||||
(decodedMakerAssetData as ERC721AssetData).tokenAddress,
|
|
||||||
(decodedMakerAssetData as ERC721AssetData).tokenId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// If makerToken === ZRX then we already removed it and we don't need to remove it again.
|
// If makerToken === ZRX then we already removed it and we don't need to remove it again.
|
||||||
if ((decodedMakerAssetData as ERC20AssetData).tokenAddress !== this._zrxTokenAddress) {
|
const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
|
||||||
|
if (
|
||||||
|
assetDataUtils.isERC20AssetData(decodedMakerAssetData) &&
|
||||||
|
decodedMakerAssetData.tokenAddress !== this._zrxTokenAddress
|
||||||
|
) {
|
||||||
this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress);
|
this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress);
|
||||||
}
|
}
|
||||||
this._removeFromMakerDependentOrderhashes(signedOrder);
|
this._removeFromMakerDependentOrderhashes(signedOrder);
|
||||||
@ -167,6 +149,18 @@ export class DependentOrderHashesTracker {
|
|||||||
tokenId.toString()
|
tokenId.toString()
|
||||||
].add(orderHash);
|
].add(orderHash);
|
||||||
}
|
}
|
||||||
|
private _addAssetDataToDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
|
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||||
|
this._addToERC20DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress);
|
||||||
|
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
|
this._addToERC721DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress, decodedAssetData.tokenId);
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||||
|
this._addAssetDataToDependentOrderHashes(signedOrder, nestedAssetDataElement),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void {
|
private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void {
|
||||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
if (_.isUndefined(this._orderHashesByMakerAddress[signedOrder.makerAddress])) {
|
if (_.isUndefined(this._orderHashesByMakerAddress[signedOrder.makerAddress])) {
|
||||||
@ -230,4 +224,20 @@ export class DependentOrderHashesTracker {
|
|||||||
delete this._orderHashesByMakerAddress[signedOrder.makerAddress];
|
delete this._orderHashesByMakerAddress[signedOrder.makerAddress];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private _removeAssetDataFromDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
|
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||||
|
this._removeFromERC20DependentOrderhashes(signedOrder, decodedAssetData.tokenAddress);
|
||||||
|
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
|
this._removeFromERC721DependentOrderhashes(
|
||||||
|
signedOrder,
|
||||||
|
decodedAssetData.tokenAddress,
|
||||||
|
decodedAssetData.tokenId,
|
||||||
|
);
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||||
|
this._removeAssetDataFromDependentOrderHashes(signedOrder, nestedAssetDataElement),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,14 +161,7 @@ export class OrderWatcher {
|
|||||||
this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder);
|
this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder);
|
||||||
|
|
||||||
const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData];
|
const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData];
|
||||||
_.each(orderAssetDatas, assetData => {
|
_.each(orderAssetDatas, assetData => this._addAssetDataToAbiDecoder(assetData));
|
||||||
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
|
||||||
if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
|
|
||||||
this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress);
|
|
||||||
} else if (decodedAssetData.assetProxyId === AssetProxyId.ERC721) {
|
|
||||||
this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Removes an order from the orderWatcher
|
* Removes an order from the orderWatcher
|
||||||
@ -236,31 +229,71 @@ export class OrderWatcher {
|
|||||||
await this._emitRevalidateOrdersAsync([orderHash]);
|
await this._emitRevalidateOrdersAsync([orderHash]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private _addAssetDataToAbiDecoder(assetData: string): void {
|
||||||
|
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||||
|
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||||
|
this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress);
|
||||||
|
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||||
|
this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress);
|
||||||
|
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||||
|
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||||
|
this._addAssetDataToAbiDecoder(nestedAssetDataElement),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private _deleteLazyStoreBalance(assetData: string, userAddress: string): void {
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
switch (assetProxyId) {
|
||||||
|
case AssetProxyId.ERC20:
|
||||||
|
case AssetProxyId.ERC721:
|
||||||
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(assetData, userAddress);
|
||||||
|
break;
|
||||||
|
case AssetProxyId.MultiAsset:
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||||
|
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||||
|
this._deleteLazyStoreBalance(nestedAssetDataElement, userAddress),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private _deleteLazyStoreProxyAllowance(assetData: string, userAddress: string): void {
|
||||||
|
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||||
|
switch (assetProxyId) {
|
||||||
|
case AssetProxyId.ERC20:
|
||||||
|
case AssetProxyId.ERC721:
|
||||||
|
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(assetData, userAddress);
|
||||||
|
break;
|
||||||
|
case AssetProxyId.MultiAsset:
|
||||||
|
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||||
|
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||||
|
this._deleteLazyStoreProxyAllowance(nestedAssetDataElement, userAddress),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
private _cleanupOrderRelatedState(orderHash: string): void {
|
private _cleanupOrderRelatedState(orderHash: string): void {
|
||||||
const signedOrder = this._orderByOrderHash[orderHash];
|
const signedOrder = this._orderByOrderHash[orderHash];
|
||||||
|
|
||||||
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
|
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
|
||||||
this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash);
|
this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash);
|
||||||
|
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.makerAssetData, signedOrder.makerAddress);
|
this._deleteLazyStoreBalance(signedOrder.makerAssetData, signedOrder.makerAddress);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(
|
this._deleteLazyStoreProxyAllowance(signedOrder.makerAssetData, signedOrder.makerAddress);
|
||||||
signedOrder.makerAssetData,
|
this._deleteLazyStoreBalance(signedOrder.takerAssetData, signedOrder.takerAddress);
|
||||||
signedOrder.makerAddress,
|
this._deleteLazyStoreProxyAllowance(signedOrder.takerAssetData, signedOrder.takerAddress);
|
||||||
);
|
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.takerAssetData, signedOrder.takerAddress);
|
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(
|
|
||||||
signedOrder.takerAssetData,
|
|
||||||
signedOrder.takerAddress,
|
|
||||||
);
|
|
||||||
|
|
||||||
const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData();
|
const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData();
|
||||||
if (!signedOrder.makerFee.isZero()) {
|
if (!signedOrder.makerFee.isZero()) {
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxAssetData, signedOrder.makerAddress);
|
this._deleteLazyStoreBalance(zrxAssetData, signedOrder.makerAddress);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxAssetData, signedOrder.makerAddress);
|
this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.makerAddress);
|
||||||
}
|
}
|
||||||
if (!signedOrder.takerFee.isZero()) {
|
if (!signedOrder.takerFee.isZero()) {
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxAssetData, signedOrder.takerAddress);
|
this._deleteLazyStoreBalance(zrxAssetData, signedOrder.takerAddress);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxAssetData, signedOrder.takerAddress);
|
this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.takerAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _onOrderExpired(orderHash: string): void {
|
private _onOrderExpired(orderHash: string): void {
|
||||||
@ -302,7 +335,7 @@ export class OrderWatcher {
|
|||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as ERC20TokenApprovalEventArgs;
|
const args = decodedLog.args as ERC20TokenApprovalEventArgs;
|
||||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(tokenAssetData, args._owner);
|
this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||||
args._owner,
|
args._owner,
|
||||||
@ -315,7 +348,7 @@ export class OrderWatcher {
|
|||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as ERC721TokenApprovalEventArgs;
|
const args = decodedLog.args as ERC721TokenApprovalEventArgs;
|
||||||
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
|
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(tokenAssetData, args._owner);
|
this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||||
args._owner,
|
args._owner,
|
||||||
@ -333,8 +366,8 @@ export class OrderWatcher {
|
|||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as ERC20TokenTransferEventArgs;
|
const args = decodedLog.args as ERC20TokenTransferEventArgs;
|
||||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._from);
|
this._deleteLazyStoreBalance(tokenAssetData, args._from);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._to);
|
this._deleteLazyStoreBalance(tokenAssetData, args._to);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||||
args._from,
|
args._from,
|
||||||
@ -347,8 +380,8 @@ export class OrderWatcher {
|
|||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as ERC721TokenTransferEventArgs;
|
const args = decodedLog.args as ERC721TokenTransferEventArgs;
|
||||||
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
|
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._from);
|
this._deleteLazyStoreBalance(tokenAssetData, args._from);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._to);
|
this._deleteLazyStoreBalance(tokenAssetData, args._to);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||||
args._from,
|
args._from,
|
||||||
@ -375,7 +408,7 @@ export class OrderWatcher {
|
|||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as WETH9DepositEventArgs;
|
const args = decodedLog.args as WETH9DepositEventArgs;
|
||||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._owner);
|
this._deleteLazyStoreBalance(tokenAssetData, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||||
args._owner,
|
args._owner,
|
||||||
@ -388,7 +421,7 @@ export class OrderWatcher {
|
|||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as WETH9WithdrawalEventArgs;
|
const args = decodedLog.args as WETH9WithdrawalEventArgs;
|
||||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._owner);
|
this._deleteLazyStoreBalance(tokenAssetData, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||||
args._owner,
|
args._owner,
|
||||||
|
@ -675,5 +675,213 @@ describe('OrderWatcher', () => {
|
|||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('multiAsset', async () => {
|
||||||
|
const tokenId = new BigNumber(42);
|
||||||
|
const [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses();
|
||||||
|
const makerErc721AssetData = assetDataUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId);
|
||||||
|
const fillableErc721Amount = new BigNumber(1);
|
||||||
|
const [makerErc20TokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
|
||||||
|
const makerErc20AssetData = assetDataUtils.encodeERC20AssetData(makerErc20TokenAddress);
|
||||||
|
const fillableErc20Amount = new BigNumber(2);
|
||||||
|
const multiAssetAmounts = [fillableErc721Amount, fillableErc20Amount];
|
||||||
|
const nestedAssetData = [makerErc721AssetData, makerErc20AssetData];
|
||||||
|
const makerMultiAssetData = assetDataUtils.encodeMultiAssetData(multiAssetAmounts, nestedAssetData);
|
||||||
|
it('should emit orderStateInvalid when maker allowance of ERC721 token set to 0 for watched order', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableErc721Amount,
|
||||||
|
);
|
||||||
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
await contractWrappers.erc721Token.setApprovalAsync(
|
||||||
|
makerErc721TokenAddress,
|
||||||
|
constants.NULL_ADDRESS,
|
||||||
|
tokenId,
|
||||||
|
);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
it('should emit orderStateInvalid when maker allowance for all of ERC721 token set to 0 for watched order', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableErc721Amount,
|
||||||
|
);
|
||||||
|
await contractWrappers.erc721Token.setApprovalAsync(
|
||||||
|
makerErc721TokenAddress,
|
||||||
|
constants.NULL_ADDRESS,
|
||||||
|
tokenId,
|
||||||
|
);
|
||||||
|
let isApproved = true;
|
||||||
|
await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
|
||||||
|
makerErc721TokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
isApproved,
|
||||||
|
);
|
||||||
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
isApproved = false;
|
||||||
|
await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
|
||||||
|
makerErc721TokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
isApproved,
|
||||||
|
);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
it('should emit orderStateInvalid when maker moves ERC721 backing watched order', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableErc721Amount,
|
||||||
|
);
|
||||||
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
await contractWrappers.erc721Token.transferFromAsync(
|
||||||
|
makerErc721TokenAddress,
|
||||||
|
coinbase,
|
||||||
|
makerAddress,
|
||||||
|
tokenId,
|
||||||
|
);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
it('should emit orderStateInvalid when maker allowance of ERC20 token set to 0 for watched order', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableErc721Amount,
|
||||||
|
);
|
||||||
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
await contractWrappers.erc20Token.setProxyAllowanceAsync(
|
||||||
|
makerErc20TokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
new BigNumber(0),
|
||||||
|
);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
it('should not emit an orderState event when irrelevant ERC20 Transfer event received', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => {
|
||||||
|
throw new Error('OrderState callback fired for irrelevant order');
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
const notTheMaker = userAddresses[0];
|
||||||
|
const anyRecipient = takerAddress;
|
||||||
|
const transferAmount = new BigNumber(2);
|
||||||
|
await contractWrappers.erc20Token.transferAsync(
|
||||||
|
makerTokenAddress,
|
||||||
|
notTheMaker,
|
||||||
|
anyRecipient,
|
||||||
|
transferAmount,
|
||||||
|
);
|
||||||
|
setTimeout(() => {
|
||||||
|
done();
|
||||||
|
}, TIMEOUT_MS);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
it('should emit orderStateInvalid when makerAddress moves ERC20 balance backing watched order', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
);
|
||||||
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
const anyRecipient = takerAddress;
|
||||||
|
const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(
|
||||||
|
makerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
);
|
||||||
|
await contractWrappers.erc20Token.transferAsync(
|
||||||
|
makerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
anyRecipient,
|
||||||
|
makerBalance,
|
||||||
|
);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
// TODO(abandeali1): The following test will fail until the MAP has been deployed and activated.
|
||||||
|
it.skip('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerMultiAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
);
|
||||||
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
|
});
|
||||||
|
orderWatcher.subscribe(callback);
|
||||||
|
|
||||||
|
await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}); // tslint:disable:max-file-line-count
|
}); // tslint:disable:max-file-line-count
|
||||||
|
@ -26,7 +26,7 @@ interface WsMessage {
|
|||||||
data: string;
|
data: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe.only('OrderWatcherWebSocketServer', async () => {
|
describe('OrderWatcherWebSocketServer', async () => {
|
||||||
let contractWrappers: ContractWrappers;
|
let contractWrappers: ContractWrappers;
|
||||||
let wsServer: OrderWatcherWebSocketServer;
|
let wsServer: OrderWatcherWebSocketServer;
|
||||||
let wsClient: WebSocket.w3cwebsocket;
|
let wsClient: WebSocket.w3cwebsocket;
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
"@0x/contract-artifacts": "^1.0.1",
|
"@0x/contract-artifacts": "^1.0.1",
|
||||||
"@0x/contract-wrappers": "^3.0.0",
|
"@0x/contract-wrappers": "^3.0.0",
|
||||||
"@0x/dev-utils": "^1.0.21",
|
"@0x/dev-utils": "^1.0.21",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^3.0.7",
|
||||||
"@0x/subproviders": "^2.1.8",
|
"@0x/subproviders": "^2.1.8",
|
||||||
"@0x/types": "^1.4.1",
|
"@0x/types": "^1.4.1",
|
||||||
"@0x/utils": "^2.0.8",
|
"@0x/utils": "^2.0.8",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Column, Entity, PrimaryColumn } from 'typeorm';
|
import { Column, Entity, PrimaryColumn } from 'typeorm';
|
||||||
|
|
||||||
import { OrderType } from '../types';
|
|
||||||
import { bigNumberTransformer, numberToBigIntTransformer } from '../utils';
|
import { bigNumberTransformer, numberToBigIntTransformer } from '../utils';
|
||||||
|
|
||||||
@Entity({ name: 'token_orderbook_snapshots', schema: 'raw' })
|
@Entity({ name: 'token_orderbook_snapshots', schema: 'raw' })
|
||||||
@ -11,7 +10,7 @@ export class TokenOrderbookSnapshot {
|
|||||||
@PrimaryColumn({ name: 'source' })
|
@PrimaryColumn({ name: 'source' })
|
||||||
public source!: string;
|
public source!: string;
|
||||||
@PrimaryColumn({ name: 'order_type' })
|
@PrimaryColumn({ name: 'order_type' })
|
||||||
public orderType!: OrderType;
|
public orderType!: string;
|
||||||
@PrimaryColumn({ name: 'price', type: 'numeric', transformer: bigNumberTransformer })
|
@PrimaryColumn({ name: 'price', type: 'numeric', transformer: bigNumberTransformer })
|
||||||
public price!: BigNumber;
|
public price!: BigNumber;
|
||||||
@PrimaryColumn({ name: 'base_asset_symbol' })
|
@PrimaryColumn({ name: 'base_asset_symbol' })
|
||||||
|
@ -23,8 +23,12 @@ export function parseDdexOrders(
|
|||||||
): TokenOrder[] {
|
): TokenOrder[] {
|
||||||
const aggregatedBids = aggregateOrders(ddexOrderbook.bids);
|
const aggregatedBids = aggregateOrders(ddexOrderbook.bids);
|
||||||
const aggregatedAsks = aggregateOrders(ddexOrderbook.asks);
|
const aggregatedAsks = aggregateOrders(ddexOrderbook.asks);
|
||||||
const parsedBids = aggregatedBids.map(order => parseDdexOrder(ddexMarket, observedTimestamp, 'bid', source, order));
|
const parsedBids = aggregatedBids.map(order =>
|
||||||
const parsedAsks = aggregatedAsks.map(order => parseDdexOrder(ddexMarket, observedTimestamp, 'ask', source, order));
|
parseDdexOrder(ddexMarket, observedTimestamp, OrderType.Bid, source, order),
|
||||||
|
);
|
||||||
|
const parsedAsks = aggregatedAsks.map(order =>
|
||||||
|
parseDdexOrder(ddexMarket, observedTimestamp, OrderType.Ask, source, order),
|
||||||
|
);
|
||||||
return parsedBids.concat(parsedAsks);
|
return parsedBids.concat(parsedAsks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { LogWithDecodedArgs } from 'ethereum-types';
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { ExchangeCancelEvent, ExchangeCancelUpToEvent, ExchangeFillEvent } from '../../entities';
|
import { ExchangeCancelEvent, ExchangeCancelUpToEvent, ExchangeFillEvent } from '../../entities';
|
||||||
import { bigNumbertoStringOrNull } from '../../utils';
|
import { bigNumbertoStringOrNull, convertAssetProxyIdToType } from '../../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses raw event logs for a fill event and returns an array of
|
* Parses raw event logs for a fill event and returns an array of
|
||||||
@ -40,9 +40,7 @@ export const parseExchangeCancelUpToEvents: (
|
|||||||
*/
|
*/
|
||||||
export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<ExchangeFillEventArgs>): ExchangeFillEvent {
|
export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<ExchangeFillEventArgs>): ExchangeFillEvent {
|
||||||
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
|
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
|
||||||
const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
|
|
||||||
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
|
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
|
||||||
const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
|
|
||||||
const exchangeFillEvent = new ExchangeFillEvent();
|
const exchangeFillEvent = new ExchangeFillEvent();
|
||||||
exchangeFillEvent.contractAddress = eventLog.address as string;
|
exchangeFillEvent.contractAddress = eventLog.address as string;
|
||||||
exchangeFillEvent.blockNumber = eventLog.blockNumber as number;
|
exchangeFillEvent.blockNumber = eventLog.blockNumber as number;
|
||||||
@ -59,16 +57,24 @@ export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<Exchang
|
|||||||
exchangeFillEvent.takerFeePaid = eventLog.args.takerFeePaid;
|
exchangeFillEvent.takerFeePaid = eventLog.args.takerFeePaid;
|
||||||
exchangeFillEvent.orderHash = eventLog.args.orderHash;
|
exchangeFillEvent.orderHash = eventLog.args.orderHash;
|
||||||
exchangeFillEvent.rawMakerAssetData = eventLog.args.makerAssetData;
|
exchangeFillEvent.rawMakerAssetData = eventLog.args.makerAssetData;
|
||||||
exchangeFillEvent.makerAssetType = makerAssetType;
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
exchangeFillEvent.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId);
|
||||||
exchangeFillEvent.makerAssetProxyId = makerAssetData.assetProxyId;
|
exchangeFillEvent.makerAssetProxyId = makerAssetData.assetProxyId;
|
||||||
exchangeFillEvent.makerTokenAddress = makerAssetData.tokenAddress;
|
// HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
|
||||||
|
exchangeFillEvent.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData)
|
||||||
|
? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0].tokenAddress
|
||||||
|
: makerAssetData.tokenAddress;
|
||||||
// tslint has a false positive here. Type assertion is required.
|
// tslint has a false positive here. Type assertion is required.
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
exchangeFillEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
|
exchangeFillEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
|
||||||
exchangeFillEvent.rawTakerAssetData = eventLog.args.takerAssetData;
|
exchangeFillEvent.rawTakerAssetData = eventLog.args.takerAssetData;
|
||||||
exchangeFillEvent.takerAssetType = takerAssetType;
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
exchangeFillEvent.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId);
|
||||||
exchangeFillEvent.takerAssetProxyId = takerAssetData.assetProxyId;
|
exchangeFillEvent.takerAssetProxyId = takerAssetData.assetProxyId;
|
||||||
exchangeFillEvent.takerTokenAddress = takerAssetData.tokenAddress;
|
// HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
|
||||||
|
exchangeFillEvent.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData)
|
||||||
|
? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0].tokenAddress
|
||||||
|
: takerAssetData.tokenAddress;
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
exchangeFillEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
|
exchangeFillEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
|
||||||
return exchangeFillEvent;
|
return exchangeFillEvent;
|
||||||
@ -83,9 +89,7 @@ export function _convertToExchangeCancelEvent(
|
|||||||
eventLog: LogWithDecodedArgs<ExchangeCancelEventArgs>,
|
eventLog: LogWithDecodedArgs<ExchangeCancelEventArgs>,
|
||||||
): ExchangeCancelEvent {
|
): ExchangeCancelEvent {
|
||||||
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
|
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
|
||||||
const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
|
|
||||||
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
|
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
|
||||||
const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
|
|
||||||
const exchangeCancelEvent = new ExchangeCancelEvent();
|
const exchangeCancelEvent = new ExchangeCancelEvent();
|
||||||
exchangeCancelEvent.contractAddress = eventLog.address as string;
|
exchangeCancelEvent.contractAddress = eventLog.address as string;
|
||||||
exchangeCancelEvent.blockNumber = eventLog.blockNumber as number;
|
exchangeCancelEvent.blockNumber = eventLog.blockNumber as number;
|
||||||
@ -98,15 +102,23 @@ export function _convertToExchangeCancelEvent(
|
|||||||
exchangeCancelEvent.senderAddress = eventLog.args.senderAddress;
|
exchangeCancelEvent.senderAddress = eventLog.args.senderAddress;
|
||||||
exchangeCancelEvent.orderHash = eventLog.args.orderHash;
|
exchangeCancelEvent.orderHash = eventLog.args.orderHash;
|
||||||
exchangeCancelEvent.rawMakerAssetData = eventLog.args.makerAssetData;
|
exchangeCancelEvent.rawMakerAssetData = eventLog.args.makerAssetData;
|
||||||
exchangeCancelEvent.makerAssetType = makerAssetType;
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
exchangeCancelEvent.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId);
|
||||||
exchangeCancelEvent.makerAssetProxyId = makerAssetData.assetProxyId;
|
exchangeCancelEvent.makerAssetProxyId = makerAssetData.assetProxyId;
|
||||||
exchangeCancelEvent.makerTokenAddress = makerAssetData.tokenAddress;
|
// HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
|
||||||
|
exchangeCancelEvent.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData)
|
||||||
|
? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0].tokenAddress
|
||||||
|
: makerAssetData.tokenAddress;
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
exchangeCancelEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
|
exchangeCancelEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
|
||||||
exchangeCancelEvent.rawTakerAssetData = eventLog.args.takerAssetData;
|
exchangeCancelEvent.rawTakerAssetData = eventLog.args.takerAssetData;
|
||||||
exchangeCancelEvent.takerAssetType = takerAssetType;
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
exchangeCancelEvent.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId);
|
||||||
exchangeCancelEvent.takerAssetProxyId = takerAssetData.assetProxyId;
|
exchangeCancelEvent.takerAssetProxyId = takerAssetData.assetProxyId;
|
||||||
exchangeCancelEvent.takerTokenAddress = takerAssetData.tokenAddress;
|
// HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
|
||||||
|
exchangeCancelEvent.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData)
|
||||||
|
? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0].tokenAddress
|
||||||
|
: takerAssetData.tokenAddress;
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
exchangeCancelEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
|
exchangeCancelEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
|
||||||
return exchangeCancelEvent;
|
return exchangeCancelEvent;
|
||||||
|
@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils';
|
|||||||
|
|
||||||
import { aggregateOrders } from '../utils';
|
import { aggregateOrders } from '../utils';
|
||||||
|
|
||||||
import { IdexOrder, IdexOrderbook, IdexOrderParam } from '../../data_sources/idex';
|
import { IdexOrderbook, IdexOrderParam } from '../../data_sources/idex';
|
||||||
import { TokenOrderbookSnapshot as TokenOrder } from '../../entities';
|
import { TokenOrderbookSnapshot as TokenOrder } from '../../entities';
|
||||||
import { OrderType } from '../../types';
|
import { OrderType } from '../../types';
|
||||||
|
|
||||||
@ -21,7 +21,9 @@ export function parseIdexOrders(idexOrderbook: IdexOrderbook, observedTimestamp:
|
|||||||
const idexBidOrder = idexOrderbook.bids[0];
|
const idexBidOrder = idexOrderbook.bids[0];
|
||||||
const parsedBids =
|
const parsedBids =
|
||||||
aggregatedBids.length > 0
|
aggregatedBids.length > 0
|
||||||
? aggregatedBids.map(order => parseIdexOrder(idexBidOrder.params, observedTimestamp, 'bid', source, order))
|
? aggregatedBids.map(order =>
|
||||||
|
parseIdexOrder(idexBidOrder.params, observedTimestamp, OrderType.Bid, source, order),
|
||||||
|
)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const aggregatedAsks = aggregateOrders(idexOrderbook.asks);
|
const aggregatedAsks = aggregateOrders(idexOrderbook.asks);
|
||||||
@ -29,7 +31,9 @@ export function parseIdexOrders(idexOrderbook: IdexOrderbook, observedTimestamp:
|
|||||||
const idexAskOrder = idexOrderbook.asks[0];
|
const idexAskOrder = idexOrderbook.asks[0];
|
||||||
const parsedAsks =
|
const parsedAsks =
|
||||||
aggregatedAsks.length > 0
|
aggregatedAsks.length > 0
|
||||||
? aggregatedAsks.map(order => parseIdexOrder(idexAskOrder.params, observedTimestamp, 'ask', source, order))
|
? aggregatedAsks.map(order =>
|
||||||
|
parseIdexOrder(idexAskOrder.params, observedTimestamp, OrderType.Ask, source, order),
|
||||||
|
)
|
||||||
: [];
|
: [];
|
||||||
return parsedBids.concat(parsedAsks);
|
return parsedBids.concat(parsedAsks);
|
||||||
}
|
}
|
||||||
@ -62,7 +66,7 @@ export function parseIdexOrder(
|
|||||||
tokenOrder.baseVolume = amount;
|
tokenOrder.baseVolume = amount;
|
||||||
tokenOrder.quoteVolume = price.times(amount);
|
tokenOrder.quoteVolume = price.times(amount);
|
||||||
|
|
||||||
if (orderType === 'bid') {
|
if (orderType === OrderType.Bid) {
|
||||||
tokenOrder.baseAssetSymbol = idexOrderParam.buySymbol;
|
tokenOrder.baseAssetSymbol = idexOrderParam.buySymbol;
|
||||||
tokenOrder.baseAssetAddress = idexOrderParam.tokenBuy;
|
tokenOrder.baseAssetAddress = idexOrderParam.tokenBuy;
|
||||||
tokenOrder.quoteAssetSymbol = idexOrderParam.sellSymbol;
|
tokenOrder.quoteAssetSymbol = idexOrderParam.sellSymbol;
|
||||||
|
@ -23,13 +23,13 @@ export function parseOasisOrders(
|
|||||||
observedTimestamp: number,
|
observedTimestamp: number,
|
||||||
source: string,
|
source: string,
|
||||||
): TokenOrder[] {
|
): TokenOrder[] {
|
||||||
const aggregatedBids = aggregateOrders(R.filter(R.propEq('act', 'bid'), oasisOrderbook));
|
const aggregatedBids = aggregateOrders(R.filter(R.propEq('act', OrderType.Bid), oasisOrderbook));
|
||||||
const aggregatedAsks = aggregateOrders(R.filter(R.propEq('act', 'ask'), oasisOrderbook));
|
const aggregatedAsks = aggregateOrders(R.filter(R.propEq('act', OrderType.Ask), oasisOrderbook));
|
||||||
const parsedBids = aggregatedBids.map(order =>
|
const parsedBids = aggregatedBids.map(order =>
|
||||||
parseOasisOrder(oasisMarket, observedTimestamp, 'bid', source, order),
|
parseOasisOrder(oasisMarket, observedTimestamp, OrderType.Bid, source, order),
|
||||||
);
|
);
|
||||||
const parsedAsks = aggregatedAsks.map(order =>
|
const parsedAsks = aggregatedAsks.map(order =>
|
||||||
parseOasisOrder(oasisMarket, observedTimestamp, 'ask', source, order),
|
parseOasisOrder(oasisMarket, observedTimestamp, OrderType.Ask, source, order),
|
||||||
);
|
);
|
||||||
return parsedBids.concat(parsedAsks);
|
return parsedBids.concat(parsedAsks);
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,10 @@ export function parseParadexOrders(
|
|||||||
source: string,
|
source: string,
|
||||||
): TokenOrder[] {
|
): TokenOrder[] {
|
||||||
const parsedBids = paradexOrderbookResponse.bids.map(order =>
|
const parsedBids = paradexOrderbookResponse.bids.map(order =>
|
||||||
parseParadexOrder(paradexMarket, observedTimestamp, 'bid', source, order),
|
parseParadexOrder(paradexMarket, observedTimestamp, OrderType.Bid, source, order),
|
||||||
);
|
);
|
||||||
const parsedAsks = paradexOrderbookResponse.asks.map(order =>
|
const parsedAsks = paradexOrderbookResponse.asks.map(order =>
|
||||||
parseParadexOrder(paradexMarket, observedTimestamp, 'ask', source, order),
|
parseParadexOrder(paradexMarket, observedTimestamp, OrderType.Ask, source, order),
|
||||||
);
|
);
|
||||||
return parsedBids.concat(parsedAsks);
|
return parsedBids.concat(parsedAsks);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { AssetProxyId, ERC721AssetData } from '@0x/types';
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { SraOrder } from '../../entities';
|
import { SraOrder } from '../../entities';
|
||||||
import { bigNumbertoStringOrNull } from '../../utils';
|
import { bigNumbertoStringOrNull, convertAssetProxyIdToType } from '../../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a raw order response from an SRA endpoint and returns an array of
|
* Parses a raw order response from an SRA endpoint and returns an array of
|
||||||
@ -22,9 +22,7 @@ export function parseSraOrders(rawOrdersResponse: OrdersResponse): SraOrder[] {
|
|||||||
export function _convertToEntity(apiOrder: APIOrder): SraOrder {
|
export function _convertToEntity(apiOrder: APIOrder): SraOrder {
|
||||||
// TODO(albrow): refactor out common asset data decoding code.
|
// TODO(albrow): refactor out common asset data decoding code.
|
||||||
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(apiOrder.order.makerAssetData);
|
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(apiOrder.order.makerAssetData);
|
||||||
const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
|
|
||||||
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(apiOrder.order.takerAssetData);
|
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(apiOrder.order.takerAssetData);
|
||||||
const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
|
|
||||||
|
|
||||||
const sraOrder = new SraOrder();
|
const sraOrder = new SraOrder();
|
||||||
sraOrder.exchangeAddress = apiOrder.order.exchangeAddress;
|
sraOrder.exchangeAddress = apiOrder.order.exchangeAddress;
|
||||||
@ -43,16 +41,24 @@ export function _convertToEntity(apiOrder: APIOrder): SraOrder {
|
|||||||
sraOrder.signature = apiOrder.order.signature;
|
sraOrder.signature = apiOrder.order.signature;
|
||||||
|
|
||||||
sraOrder.rawMakerAssetData = apiOrder.order.makerAssetData;
|
sraOrder.rawMakerAssetData = apiOrder.order.makerAssetData;
|
||||||
sraOrder.makerAssetType = makerAssetType;
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
sraOrder.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId);
|
||||||
sraOrder.makerAssetProxyId = makerAssetData.assetProxyId;
|
sraOrder.makerAssetProxyId = makerAssetData.assetProxyId;
|
||||||
sraOrder.makerTokenAddress = makerAssetData.tokenAddress;
|
// HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
|
||||||
|
sraOrder.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData)
|
||||||
|
? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.makerAssetData).nestedAssetData[0].tokenAddress
|
||||||
|
: makerAssetData.tokenAddress;
|
||||||
// tslint has a false positive here. Type assertion is required.
|
// tslint has a false positive here. Type assertion is required.
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
sraOrder.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
|
sraOrder.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
|
||||||
sraOrder.rawTakerAssetData = apiOrder.order.takerAssetData;
|
sraOrder.rawTakerAssetData = apiOrder.order.takerAssetData;
|
||||||
sraOrder.takerAssetType = takerAssetType;
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
sraOrder.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId);
|
||||||
sraOrder.takerAssetProxyId = takerAssetData.assetProxyId;
|
sraOrder.takerAssetProxyId = takerAssetData.assetProxyId;
|
||||||
sraOrder.takerTokenAddress = takerAssetData.tokenAddress;
|
// HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
|
||||||
|
sraOrder.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData)
|
||||||
|
? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.takerAssetData).nestedAssetData[0].tokenAddress
|
||||||
|
: takerAssetData.tokenAddress;
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
sraOrder.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
|
sraOrder.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
|
||||||
|
|
||||||
|
@ -1,2 +1,9 @@
|
|||||||
export type AssetType = 'erc20' | 'erc721';
|
export enum AssetType {
|
||||||
export type OrderType = 'bid' | 'ask';
|
ERC20 = 'erc20',
|
||||||
|
ERC721 = 'erc721',
|
||||||
|
MultiAsset = 'multiAsset',
|
||||||
|
}
|
||||||
|
export enum OrderType {
|
||||||
|
Bid = 'bid',
|
||||||
|
Ask = 'ask',
|
||||||
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
import { AssetProxyId } from '@0x/types';
|
||||||
|
|
||||||
|
import { AssetType } from '../../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an assetProxyId to its string equivalent
|
||||||
|
* @param assetProxyId Id of AssetProxy
|
||||||
|
*/
|
||||||
|
export function convertAssetProxyIdToType(assetProxyId: AssetProxyId): AssetType {
|
||||||
|
switch (assetProxyId) {
|
||||||
|
case AssetProxyId.ERC20:
|
||||||
|
return AssetType.ERC20;
|
||||||
|
case AssetProxyId.ERC721:
|
||||||
|
return AssetType.ERC721;
|
||||||
|
case AssetProxyId.MultiAsset:
|
||||||
|
return AssetType.MultiAsset;
|
||||||
|
default:
|
||||||
|
throw new Error(`${assetProxyId} not a supported assetProxyId`);
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export * from './big_number';
|
export * from './big_number';
|
||||||
export * from './number_to_bigint';
|
export * from './number_to_bigint';
|
||||||
|
export * from './asset_proxy_id_types';
|
||||||
|
@ -31,13 +31,13 @@ describe('ddex_orders', () => {
|
|||||||
amountDecimals: 0,
|
amountDecimals: 0,
|
||||||
};
|
};
|
||||||
const observedTimestamp: number = Date.now();
|
const observedTimestamp: number = Date.now();
|
||||||
const orderType: OrderType = 'bid';
|
const orderType: OrderType = OrderType.Bid;
|
||||||
const source: string = 'ddex';
|
const source: string = 'ddex';
|
||||||
|
|
||||||
const expected = new TokenOrder();
|
const expected = new TokenOrder();
|
||||||
expected.source = 'ddex';
|
expected.source = 'ddex';
|
||||||
expected.observedTimestamp = observedTimestamp;
|
expected.observedTimestamp = observedTimestamp;
|
||||||
expected.orderType = 'bid';
|
expected.orderType = OrderType.Bid;
|
||||||
expected.price = new BigNumber(0.5);
|
expected.price = new BigNumber(0.5);
|
||||||
// ddex currently confuses base and quote assets.
|
// ddex currently confuses base and quote assets.
|
||||||
// Switch them to maintain our internal consistency.
|
// Switch them to maintain our internal consistency.
|
||||||
|
@ -6,6 +6,7 @@ import 'mocha';
|
|||||||
|
|
||||||
import { ExchangeFillEvent } from '../../../src/entities';
|
import { ExchangeFillEvent } from '../../../src/entities';
|
||||||
import { _convertToExchangeFillEvent } from '../../../src/parsers/events/exchange_events';
|
import { _convertToExchangeFillEvent } from '../../../src/parsers/events/exchange_events';
|
||||||
|
import { AssetType } from '../../../src/types';
|
||||||
import { chaiSetup } from '../../utils/chai_setup';
|
import { chaiSetup } from '../../utils/chai_setup';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -62,12 +63,12 @@ describe('exchange_events', () => {
|
|||||||
expected.takerFeePaid = new BigNumber('12345');
|
expected.takerFeePaid = new BigNumber('12345');
|
||||||
expected.orderHash = '0xab12ed2cbaa5615ab690b9da75a46e53ddfcf3f1a68655b5fe0d94c75a1aac4a';
|
expected.orderHash = '0xab12ed2cbaa5615ab690b9da75a46e53ddfcf3f1a68655b5fe0d94c75a1aac4a';
|
||||||
expected.rawMakerAssetData = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
expected.rawMakerAssetData = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||||
expected.makerAssetType = 'erc20';
|
expected.makerAssetType = AssetType.ERC20;
|
||||||
expected.makerAssetProxyId = '0xf47261b0';
|
expected.makerAssetProxyId = '0xf47261b0';
|
||||||
expected.makerTokenAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
expected.makerTokenAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||||
expected.makerTokenId = null;
|
expected.makerTokenId = null;
|
||||||
expected.rawTakerAssetData = '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
|
expected.rawTakerAssetData = '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
|
||||||
expected.takerAssetType = 'erc20';
|
expected.takerAssetType = AssetType.ERC20;
|
||||||
expected.takerAssetProxyId = '0xf47261b0';
|
expected.takerAssetProxyId = '0xf47261b0';
|
||||||
expected.takerTokenAddress = '0xe41d2489571d322189246dafa5ebde1f4699f498';
|
expected.takerTokenAddress = '0xe41d2489571d322189246dafa5ebde1f4699f498';
|
||||||
expected.takerTokenId = null;
|
expected.takerTokenId = null;
|
||||||
|
@ -31,13 +31,13 @@ describe('idex_orders', () => {
|
|||||||
user: '0x212345667543456435324564345643453453333',
|
user: '0x212345667543456435324564345643453453333',
|
||||||
};
|
};
|
||||||
const observedTimestamp: number = Date.now();
|
const observedTimestamp: number = Date.now();
|
||||||
const orderType: OrderType = 'bid';
|
const orderType: OrderType = OrderType.Bid;
|
||||||
const source: string = 'idex';
|
const source: string = 'idex';
|
||||||
|
|
||||||
const expected = new TokenOrder();
|
const expected = new TokenOrder();
|
||||||
expected.source = 'idex';
|
expected.source = 'idex';
|
||||||
expected.observedTimestamp = observedTimestamp;
|
expected.observedTimestamp = observedTimestamp;
|
||||||
expected.orderType = 'bid';
|
expected.orderType = OrderType.Bid;
|
||||||
expected.price = new BigNumber(0.5);
|
expected.price = new BigNumber(0.5);
|
||||||
expected.baseAssetSymbol = 'ABC';
|
expected.baseAssetSymbol = 'ABC';
|
||||||
expected.baseAssetAddress = '0x0000000000000000000000000000000000000000';
|
expected.baseAssetAddress = '0x0000000000000000000000000000000000000000';
|
||||||
@ -65,13 +65,13 @@ describe('idex_orders', () => {
|
|||||||
user: '0x212345667543456435324564345643453453333',
|
user: '0x212345667543456435324564345643453453333',
|
||||||
};
|
};
|
||||||
const observedTimestamp: number = Date.now();
|
const observedTimestamp: number = Date.now();
|
||||||
const orderType: OrderType = 'ask';
|
const orderType: OrderType = OrderType.Ask;
|
||||||
const source: string = 'idex';
|
const source: string = 'idex';
|
||||||
|
|
||||||
const expected = new TokenOrder();
|
const expected = new TokenOrder();
|
||||||
expected.source = 'idex';
|
expected.source = 'idex';
|
||||||
expected.observedTimestamp = observedTimestamp;
|
expected.observedTimestamp = observedTimestamp;
|
||||||
expected.orderType = 'ask';
|
expected.orderType = OrderType.Ask;
|
||||||
expected.price = new BigNumber(0.5);
|
expected.price = new BigNumber(0.5);
|
||||||
expected.baseAssetSymbol = 'ABC';
|
expected.baseAssetSymbol = 'ABC';
|
||||||
expected.baseAssetAddress = '0x0000000000000000000000000000000000000000';
|
expected.baseAssetAddress = '0x0000000000000000000000000000000000000000';
|
||||||
|
@ -27,13 +27,13 @@ describe('oasis_orders', () => {
|
|||||||
low: 0,
|
low: 0,
|
||||||
};
|
};
|
||||||
const observedTimestamp: number = Date.now();
|
const observedTimestamp: number = Date.now();
|
||||||
const orderType: OrderType = 'bid';
|
const orderType: OrderType = OrderType.Bid;
|
||||||
const source: string = 'oasis';
|
const source: string = 'oasis';
|
||||||
|
|
||||||
const expected = new TokenOrder();
|
const expected = new TokenOrder();
|
||||||
expected.source = 'oasis';
|
expected.source = 'oasis';
|
||||||
expected.observedTimestamp = observedTimestamp;
|
expected.observedTimestamp = observedTimestamp;
|
||||||
expected.orderType = 'bid';
|
expected.orderType = OrderType.Bid;
|
||||||
expected.price = new BigNumber(0.5);
|
expected.price = new BigNumber(0.5);
|
||||||
expected.baseAssetSymbol = 'DEF';
|
expected.baseAssetSymbol = 'DEF';
|
||||||
expected.baseAssetAddress = null;
|
expected.baseAssetAddress = null;
|
||||||
|
@ -32,13 +32,13 @@ describe('paradex_orders', () => {
|
|||||||
quoteTokenAddress: '0x0000000000000000000000000000000000000000',
|
quoteTokenAddress: '0x0000000000000000000000000000000000000000',
|
||||||
};
|
};
|
||||||
const observedTimestamp: number = Date.now();
|
const observedTimestamp: number = Date.now();
|
||||||
const orderType: OrderType = 'bid';
|
const orderType: OrderType = OrderType.Bid;
|
||||||
const source: string = 'paradex';
|
const source: string = 'paradex';
|
||||||
|
|
||||||
const expected = new TokenOrder();
|
const expected = new TokenOrder();
|
||||||
expected.source = 'paradex';
|
expected.source = 'paradex';
|
||||||
expected.observedTimestamp = observedTimestamp;
|
expected.observedTimestamp = observedTimestamp;
|
||||||
expected.orderType = 'bid';
|
expected.orderType = OrderType.Bid;
|
||||||
expected.price = new BigNumber(0.1245);
|
expected.price = new BigNumber(0.1245);
|
||||||
expected.baseAssetSymbol = 'DEF';
|
expected.baseAssetSymbol = 'DEF';
|
||||||
expected.baseAssetAddress = '0xb45df06e38540a675fdb5b598abf2c0dbe9d6b81';
|
expected.baseAssetAddress = '0xb45df06e38540a675fdb5b598abf2c0dbe9d6b81';
|
||||||
|
@ -5,6 +5,7 @@ import 'mocha';
|
|||||||
|
|
||||||
import { SraOrder } from '../../../src/entities';
|
import { SraOrder } from '../../../src/entities';
|
||||||
import { _convertToEntity } from '../../../src/parsers/sra_orders';
|
import { _convertToEntity } from '../../../src/parsers/sra_orders';
|
||||||
|
import { AssetType } from '../../../src/types';
|
||||||
import { chaiSetup } from '../../utils/chai_setup';
|
import { chaiSetup } from '../../utils/chai_setup';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -50,12 +51,12 @@ describe('sra_orders', () => {
|
|||||||
expected.signature =
|
expected.signature =
|
||||||
'0x1b5a5d672b0d647b5797387ccbb89d822d5d2e873346b014f4ff816ff0783f2a7a0d2824d2d7042ec8ea375bc7f870963e1cb8248f1db03ddf125e27b5963aa11f03';
|
'0x1b5a5d672b0d647b5797387ccbb89d822d5d2e873346b014f4ff816ff0783f2a7a0d2824d2d7042ec8ea375bc7f870963e1cb8248f1db03ddf125e27b5963aa11f03';
|
||||||
expected.rawMakerAssetData = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
expected.rawMakerAssetData = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||||
expected.makerAssetType = 'erc20';
|
expected.makerAssetType = AssetType.ERC20;
|
||||||
expected.makerAssetProxyId = '0xf47261b0';
|
expected.makerAssetProxyId = '0xf47261b0';
|
||||||
expected.makerTokenAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
expected.makerTokenAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||||
expected.makerTokenId = null;
|
expected.makerTokenId = null;
|
||||||
expected.rawTakerAssetData = '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18';
|
expected.rawTakerAssetData = '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18';
|
||||||
expected.takerAssetType = 'erc20';
|
expected.takerAssetType = AssetType.ERC20;
|
||||||
expected.takerAssetProxyId = '0xf47261b0';
|
expected.takerAssetProxyId = '0xf47261b0';
|
||||||
expected.takerTokenAddress = '0x42d6622dece394b54999fbd73d108123806f6a18';
|
expected.takerTokenAddress = '0x42d6622dece394b54999fbd73d108123806f6a18';
|
||||||
expected.takerTokenId = null;
|
expected.takerTokenId = null;
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Add RevertReasons for DutchAuction contract",
|
"note": "Add RevertReasons for DutchAuction contract",
|
||||||
"pr": 1225
|
"pr": 1225
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add MultiAsset types",
|
||||||
|
"pr": 1363
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timestamp": 1544570656
|
"timestamp": 1544570656
|
||||||
|
@ -110,7 +110,9 @@ export type DoneCallback = (err?: Error) => void;
|
|||||||
|
|
||||||
export interface OrderRelevantState {
|
export interface OrderRelevantState {
|
||||||
makerBalance: BigNumber;
|
makerBalance: BigNumber;
|
||||||
|
makerIndividualBalances: ObjectMap<BigNumber>;
|
||||||
makerProxyAllowance: BigNumber;
|
makerProxyAllowance: BigNumber;
|
||||||
|
makerIndividualProxyAllowances: ObjectMap<BigNumber>;
|
||||||
makerFeeBalance: BigNumber;
|
makerFeeBalance: BigNumber;
|
||||||
makerFeeProxyAllowance: BigNumber;
|
makerFeeProxyAllowance: BigNumber;
|
||||||
filledTakerAssetAmount: BigNumber;
|
filledTakerAssetAmount: BigNumber;
|
||||||
@ -155,6 +157,7 @@ export enum SignatureType {
|
|||||||
export enum AssetProxyId {
|
export enum AssetProxyId {
|
||||||
ERC20 = '0xf47261b0',
|
ERC20 = '0xf47261b0',
|
||||||
ERC721 = '0x02571792',
|
ERC721 = '0x02571792',
|
||||||
|
MultiAsset = '0x94cfcdd7',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ERC20AssetData {
|
export interface ERC20AssetData {
|
||||||
@ -168,7 +171,21 @@ export interface ERC721AssetData {
|
|||||||
tokenId: BigNumber;
|
tokenId: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AssetData = ERC20AssetData | ERC721AssetData;
|
export type SingleAssetData = ERC20AssetData | ERC721AssetData;
|
||||||
|
|
||||||
|
export interface MultiAssetData {
|
||||||
|
assetProxyId: string;
|
||||||
|
amounts: BigNumber[];
|
||||||
|
nestedAssetData: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultiAssetDataWithRecursiveDecoding {
|
||||||
|
assetProxyId: string;
|
||||||
|
amounts: BigNumber[];
|
||||||
|
nestedAssetData: SingleAssetData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AssetData = SingleAssetData | MultiAssetData | MultiAssetDataWithRecursiveDecoding;
|
||||||
|
|
||||||
// TODO: DRY. These should be extracted from contract code.
|
// TODO: DRY. These should be extracted from contract code.
|
||||||
export enum RevertReason {
|
export enum RevertReason {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.1.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add `should` prefix to names of properties in EncodingRules and DecodingRules",
|
||||||
|
"pr": 1363
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -62,7 +62,7 @@ export abstract class AbstractSetDataType extends DataType {
|
|||||||
// Create a new scope in the calldata, before descending into the members of this set.
|
// Create a new scope in the calldata, before descending into the members of this set.
|
||||||
calldata.startScope();
|
calldata.startScope();
|
||||||
let value: any[] | object;
|
let value: any[] | object;
|
||||||
if (rules.structsAsObjects && !this._isArray) {
|
if (rules.shouldConvertStructsToObjects && !this._isArray) {
|
||||||
// Construct an object with values for each member of the set.
|
// Construct an object with values for each member of the set.
|
||||||
value = {};
|
value = {};
|
||||||
_.each(this._memberIndexByName, (idx: number, key: string) => {
|
_.each(this._memberIndexByName, (idx: number, key: string) => {
|
||||||
|
@ -49,7 +49,7 @@ export class Calldata {
|
|||||||
throw new Error('expected root');
|
throw new Error('expected root');
|
||||||
}
|
}
|
||||||
// Optimize, if flag set
|
// Optimize, if flag set
|
||||||
if (this._rules.optimize) {
|
if (this._rules.shouldOptimize) {
|
||||||
this._optimize();
|
this._optimize();
|
||||||
}
|
}
|
||||||
// Set offsets
|
// Set offsets
|
||||||
@ -60,7 +60,9 @@ export class Calldata {
|
|||||||
offset += block.getSizeInBytes();
|
offset += block.getSizeInBytes();
|
||||||
}
|
}
|
||||||
// Generate hex string
|
// Generate hex string
|
||||||
const hexString = this._rules.annotate ? this._toHumanReadableCallData() : this._toEvmCompatibeCallDataHex();
|
const hexString = this._rules.shouldAnnotate
|
||||||
|
? this._toHumanReadableCallData()
|
||||||
|
: this._toEvmCompatibeCallDataHex();
|
||||||
return hexString;
|
return hexString;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,7 @@ export const constants = {
|
|||||||
HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA: 0,
|
HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA: 0,
|
||||||
// Disable no-object-literal-type-assertion so we can enforce cast
|
// Disable no-object-literal-type-assertion so we can enforce cast
|
||||||
/* tslint:disable no-object-literal-type-assertion */
|
/* tslint:disable no-object-literal-type-assertion */
|
||||||
DEFAULT_DECODING_RULES: { structsAsObjects: false } as DecodingRules,
|
DEFAULT_DECODING_RULES: { shouldConvertStructsToObjects: false } as DecodingRules,
|
||||||
DEFAULT_ENCODING_RULES: { optimize: true, annotate: false } as EncodingRules,
|
DEFAULT_ENCODING_RULES: { shouldOptimize: true, shouldAnnotate: false } as EncodingRules,
|
||||||
/* tslint:enable no-object-literal-type-assertion */
|
/* tslint:enable no-object-literal-type-assertion */
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export interface DecodingRules {
|
export interface DecodingRules {
|
||||||
structsAsObjects: boolean;
|
shouldConvertStructsToObjects: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EncodingRules {
|
export interface EncodingRules {
|
||||||
optimize?: boolean;
|
shouldOptimize?: boolean;
|
||||||
annotate?: boolean;
|
shouldAnnotate?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ chaiSetup.configure();
|
|||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
||||||
const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
|
const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately.
|
||||||
describe('Array', () => {
|
describe('Array', () => {
|
||||||
it('Fixed size; Static elements', async () => {
|
it('Fixed size; Static elements', async () => {
|
||||||
// Create DataType object
|
// Create DataType object
|
||||||
@ -194,7 +194,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
|
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
@ -214,7 +214,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
|
'0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
@ -234,7 +234,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
|
'0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
@ -254,7 +254,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
|
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
@ -276,7 +276,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
|
'0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
@ -298,7 +298,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
|
'0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
@ -328,7 +328,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
|||||||
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
|
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
|
||||||
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
|
||||||
// Decode Encoded Args and validate result
|
// Decode Encoded Args and validate result
|
||||||
const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
|
const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
|
||||||
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
|
||||||
expect(decodedArgs).to.be.deep.equal(args);
|
expect(decodedArgs).to.be.deep.equal(args);
|
||||||
});
|
});
|
||||||
|
File diff suppressed because one or more lines are too long
@ -10,7 +10,7 @@ chaiSetup.configure();
|
|||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
|
describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
|
||||||
const encodingRules: AbiEncoder.EncodingRules = { optimize: true };
|
const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: true };
|
||||||
it('Duplicate Dynamic Arrays with Static Elements', async () => {
|
it('Duplicate Dynamic Arrays with Static Elements', async () => {
|
||||||
// Generate calldata
|
// Generate calldata
|
||||||
const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
|
const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
|
||||||
@ -206,7 +206,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
|
|||||||
const twoDimArray2 = twoDimArray1;
|
const twoDimArray2 = twoDimArray1;
|
||||||
const args = [twoDimArray1, twoDimArray2];
|
const args = [twoDimArray1, twoDimArray2];
|
||||||
// Validata calldata
|
// Validata calldata
|
||||||
const optimizedCalldata = method.encode(args, { optimize: false });
|
const optimizedCalldata = method.encode(args, { shouldOptimize: false });
|
||||||
const expectedOptimizedCalldata =
|
const expectedOptimizedCalldata =
|
||||||
'0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
|
'0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
|
||||||
expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
|
expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
|
||||||
|
@ -10,7 +10,7 @@ chaiSetup.configure();
|
|||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('ABI Encoder: Return Value Encoding/Decoding', () => {
|
describe('ABI Encoder: Return Value Encoding/Decoding', () => {
|
||||||
const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
|
const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately.
|
||||||
it('No Return Value', async () => {
|
it('No Return Value', async () => {
|
||||||
// Decode return value
|
// Decode return value
|
||||||
const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
|
const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
|
||||||
|
43
yarn.lock
43
yarn.lock
@ -507,7 +507,7 @@
|
|||||||
lodash "^4.17.5"
|
lodash "^4.17.5"
|
||||||
uuid "^3.1.0"
|
uuid "^3.1.0"
|
||||||
|
|
||||||
"@0x/order-utils@^2.0.0", "@0x/order-utils@^2.0.1":
|
"@0x/order-utils@^2.0.1":
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-2.0.1.tgz#8c46d7aeb9e2cce54a0822824c12427cbe5f7eb4"
|
resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-2.0.1.tgz#8c46d7aeb9e2cce54a0822824c12427cbe5f7eb4"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2100,10 +2100,6 @@ aes-js@^0.2.3:
|
|||||||
version "0.2.4"
|
version "0.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d"
|
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d"
|
||||||
|
|
||||||
aes-js@^3.1.1:
|
|
||||||
version "3.1.2"
|
|
||||||
resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a"
|
|
||||||
|
|
||||||
agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0:
|
agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
|
||||||
@ -3669,7 +3665,7 @@ bs-logger@0.x:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fast-json-stable-stringify "^2.0.0"
|
fast-json-stable-stringify "^2.0.0"
|
||||||
|
|
||||||
bs58@=4.0.1, bs58@^4.0.0:
|
bs58@=4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
|
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3692,14 +3688,6 @@ bs58check@^1.0.8:
|
|||||||
bs58 "^3.1.0"
|
bs58 "^3.1.0"
|
||||||
create-hash "^1.1.0"
|
create-hash "^1.1.0"
|
||||||
|
|
||||||
bs58check@^2.1.2:
|
|
||||||
version "2.1.2"
|
|
||||||
resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
|
|
||||||
dependencies:
|
|
||||||
bs58 "^4.0.0"
|
|
||||||
create-hash "^1.1.0"
|
|
||||||
safe-buffer "^5.1.2"
|
|
||||||
|
|
||||||
bser@^2.0.0:
|
bser@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
|
resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
|
||||||
@ -6410,19 +6398,6 @@ ethereumjs-wallet@0.6.0:
|
|||||||
utf8 "^2.1.1"
|
utf8 "^2.1.1"
|
||||||
uuid "^2.0.1"
|
uuid "^2.0.1"
|
||||||
|
|
||||||
ethereumjs-wallet@~0.6.0:
|
|
||||||
version "0.6.2"
|
|
||||||
resolved "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda"
|
|
||||||
dependencies:
|
|
||||||
aes-js "^3.1.1"
|
|
||||||
bs58check "^2.1.2"
|
|
||||||
ethereumjs-util "^5.2.0"
|
|
||||||
hdkey "^1.0.0"
|
|
||||||
safe-buffer "^5.1.2"
|
|
||||||
scrypt.js "^0.2.0"
|
|
||||||
utf8 "^3.0.0"
|
|
||||||
uuid "^3.3.2"
|
|
||||||
|
|
||||||
ethers@~4.0.4:
|
ethers@~4.0.4:
|
||||||
version "4.0.4"
|
version "4.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.4.tgz#d3f85e8b27f4b59537e06526439b0fb15b44dc65"
|
resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.4.tgz#d3f85e8b27f4b59537e06526439b0fb15b44dc65"
|
||||||
@ -7339,7 +7314,7 @@ ganache-core@0xProject/ganache-core#monorepo-dep:
|
|||||||
ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
|
ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
|
||||||
ethereumjs-util "^5.2.0"
|
ethereumjs-util "^5.2.0"
|
||||||
ethereumjs-vm "2.3.5"
|
ethereumjs-vm "2.3.5"
|
||||||
ethereumjs-wallet "~0.6.0"
|
ethereumjs-wallet "0.6.0"
|
||||||
fake-merkle-patricia-tree "~1.0.1"
|
fake-merkle-patricia-tree "~1.0.1"
|
||||||
heap "~0.2.6"
|
heap "~0.2.6"
|
||||||
js-scrypt "^0.2.0"
|
js-scrypt "^0.2.0"
|
||||||
@ -8077,14 +8052,6 @@ hdkey@^0.7.0, hdkey@^0.7.1:
|
|||||||
coinstring "^2.0.0"
|
coinstring "^2.0.0"
|
||||||
secp256k1 "^3.0.1"
|
secp256k1 "^3.0.1"
|
||||||
|
|
||||||
hdkey@^1.0.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.npmjs.org/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29"
|
|
||||||
dependencies:
|
|
||||||
coinstring "^2.0.0"
|
|
||||||
safe-buffer "^5.1.1"
|
|
||||||
secp256k1 "^3.0.1"
|
|
||||||
|
|
||||||
he@1.1.1:
|
he@1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||||
@ -16679,10 +16646,6 @@ utf8@^2.1.1:
|
|||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96"
|
resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96"
|
||||||
|
|
||||||
utf8@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
|
|
||||||
|
|
||||||
util-deprecate@~1.0.1:
|
util-deprecate@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user