merge development

This commit is contained in:
Fabio Berger 2019-03-20 14:32:26 +01:00
commit 843caf86fb
45 changed files with 1128 additions and 113 deletions

View File

@ -2,10 +2,6 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Do not reexport external dependencies", "note": "Do not reexport external dependencies",
"pr": 1682 "pr": 1682
@ -17,6 +13,10 @@
{ {
"note": "Bumped solidity version to ^0.5.5", "note": "Bumped solidity version to ^0.5.5",
"pr": 1701 "pr": 1701
},
{
"note": "Integration testing for ERC1155Proxy",
"pr": 1673
} }
] ]
}, },

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -433,6 +433,50 @@ describe('ERC1155Proxy', () => {
]; ];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
}); });
it('should successfully transfer value to a smart contract and trigger its callback, when callback `data` is NULL', async () => {
// setup test parameters
const tokenHolders = [spender, receiverContract];
const tokensToTransfer = fungibleTokens.slice(0, 1);
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {
return value.times(valueMultiplier);
});
// check balances before transfer
const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// execute transfer
const nullReceiverCallbackData = '0x';
const txReceipt = await erc1155ProxyWrapper.transferFromWithLogsAsync(
spender,
receiverContract,
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
valueMultiplier,
nullReceiverCallbackData,
authorized,
);
// check receiver log ignored extra asset data
expect(txReceipt.logs.length).to.be.equal(2);
const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<
DummyERC1155ReceiverBatchTokenReceivedEventArgs
>;
expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address);
expect(receiverLog.args.from).to.be.equal(spender);
expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1);
expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]);
expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1);
expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]);
// note - if the `extraData` is ignored then the receiver log should ignore it as well.
expect(receiverLog.args.data).to.be.deep.equal(nullReceiverCallbackData);
// check balances after transfer
const expectedFinalBalances = [
expectedInitialBalances[0].minus(totalValuesTransferred[0]),
expectedInitialBalances[1].plus(totalValuesTransferred[0]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should successfully transfer value and ignore extra assetData', async () => { it('should successfully transfer value and ignore extra assetData', async () => {
// setup test parameters // setup test parameters
const tokenHolders = [spender, receiverContract]; const tokenHolders = [spender, receiverContract];

View File

@ -1,3 +1,4 @@
import { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
import { import {
artifacts as erc20Artifacts, artifacts as erc20Artifacts,
DummyERC20TokenContract, DummyERC20TokenContract,
@ -30,6 +31,7 @@ import * as _ from 'lodash';
import { import {
artifacts, artifacts,
ERC1155ProxyWrapper,
ERC20ProxyContract, ERC20ProxyContract,
ERC20Wrapper, ERC20Wrapper,
ERC721ProxyContract, ERC721ProxyContract,
@ -77,6 +79,15 @@ describe('Asset Transfer Proxies', () => {
let erc721AFromTokenId: BigNumber; let erc721AFromTokenId: BigNumber;
let erc721BFromTokenId: BigNumber; let erc721BFromTokenId: BigNumber;
let erc1155Proxy: ERC721ProxyContract;
let erc1155ProxyWrapper: ERC1155ProxyWrapper;
let erc1155Contract: ERC1155MintableContract;
let erc1155Contract2: ERC1155MintableContract;
let erc1155Wrapper: Erc1155Wrapper;
let erc1155Wrapper2: Erc1155Wrapper;
let erc1155FungibleTokens: BigNumber[];
let erc1155NonFungibleTokensOwnedBySpender: BigNumber[];
before(async () => { before(async () => {
await blockchainLifecycle.startAsync(); await blockchainLifecycle.startAsync();
}); });
@ -127,6 +138,22 @@ describe('Asset Transfer Proxies', () => {
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
// Configure ERC115Proxy
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
await web3Wrapper.awaitTransactionSuccessAsync(
await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Configure MultiAssetProxy // Configure MultiAssetProxy
await web3Wrapper.awaitTransactionSuccessAsync( await web3Wrapper.awaitTransactionSuccessAsync(
await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, { await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
@ -146,6 +173,12 @@ describe('Asset Transfer Proxies', () => {
}), }),
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
await web3Wrapper.awaitTransactionSuccessAsync(
await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc1155Proxy.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Deploy and configure ERC20 tokens // Deploy and configure ERC20 tokens
const numDummyErc20ToDeploy = 2; const numDummyErc20ToDeploy = 2;
@ -213,6 +246,22 @@ describe('Asset Transfer Proxies', () => {
const erc721Balances = await erc721Wrapper.getBalancesAsync(); const erc721Balances = await erc721Wrapper.getBalancesAsync();
erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0]; erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0];
erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0]; erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0];
// Deploy & configure ERC1155 tokens and receiver
[erc1155Wrapper, erc1155Wrapper2] = await erc1155ProxyWrapper.deployDummyContractsAsync();
erc1155Contract = erc1155Wrapper.getContract();
erc1155Contract2 = erc1155Wrapper2.getContract();
await erc1155ProxyWrapper.setBalancesAndAllowancesAsync();
erc1155FungibleTokens = erc1155ProxyWrapper.getFungibleTokenIds();
const nonFungibleTokens = erc1155ProxyWrapper.getNonFungibleTokenIds();
const tokenBalances = await erc1155ProxyWrapper.getBalancesAsync();
erc1155NonFungibleTokensOwnedBySpender = [];
_.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => {
const nonFungibleTokenAsString = nonFungibleToken.toString();
const nonFungibleTokenHeldBySpender =
tokenBalances.nonFungible[fromAddress][erc1155Contract.address][nonFungibleTokenAsString][0];
erc1155NonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender);
});
}); });
beforeEach(async () => { beforeEach(async () => {
await blockchainLifecycle.startAsync(); await blockchainLifecycle.startAsync();
@ -944,6 +993,314 @@ describe('Asset Transfer Proxies', () => {
expect(newOwnerFromAsset1).to.be.equal(toAddress); expect(newOwnerFromAsset1).to.be.equal(toAddress);
expect(newOwnerFromAsset2).to.be.equal(toAddress); expect(newOwnerFromAsset2).to.be.equal(toAddress);
}); });
it('should transfer a fungible ERC1155 token', async () => {
// setup test parameters
const tokenHolders = [fromAddress, toAddress];
const tokensToTransfer = erc1155FungibleTokens.slice(0, 1);
const valuesToTransfer = [new BigNumber(25)];
const valueMultiplier = new BigNumber(23);
const receiverCallbackData = '0x0102030405';
// check balances before transfer
const expectedInitialBalances = [
// from
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// to
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(5);
const amounts = [valueMultiplier];
const nestedAssetData = [erc1155AssetData];
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
toAddress,
multiAssetAmount,
);
// execute transfer
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
to: multiAssetProxy.address,
data,
from: authorized,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// check balances
const totalValueTransferred = valuesToTransfer[0].times(valueMultiplier).times(multiAssetAmount);
const expectedFinalBalances = [
// from
expectedInitialBalances[0].minus(totalValueTransferred),
// to
expectedInitialBalances[1].plus(totalValueTransferred),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should successfully transfer multiple fungible tokens of the same ERC1155 contract', async () => {
// setup test parameters
const tokenHolders = [fromAddress, toAddress];
const tokensToTransfer = erc1155FungibleTokens.slice(0, 3);
const valuesToTransfer = [new BigNumber(25), new BigNumber(35), new BigNumber(45)];
const valueMultiplier = new BigNumber(23);
const receiverCallbackData = '0x0102030405';
// check balances before transfer
const expectedInitialBalances = [
// from
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// to
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(5);
const amounts = [valueMultiplier];
const nestedAssetData = [erc1155AssetData];
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
toAddress,
multiAssetAmount,
);
// execute transfer
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
to: multiAssetProxy.address,
data,
from: authorized,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// check balances
const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {
return value.times(valueMultiplier).times(multiAssetAmount);
});
const expectedFinalBalances = [
// from
expectedInitialBalances[0].minus(totalValuesTransferred[0]),
expectedInitialBalances[1].minus(totalValuesTransferred[1]),
expectedInitialBalances[2].minus(totalValuesTransferred[2]),
// to
expectedInitialBalances[3].plus(totalValuesTransferred[0]),
expectedInitialBalances[4].plus(totalValuesTransferred[1]),
expectedInitialBalances[5].plus(totalValuesTransferred[2]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should successfully transfer multiple fungible/non-fungible tokens of the same ERC1155 contract', async () => {
// setup test parameters
const tokenHolders = [fromAddress, toAddress];
const fungibleTokensToTransfer = erc1155FungibleTokens.slice(0, 1);
const nonFungibleTokensToTransfer = erc1155NonFungibleTokensOwnedBySpender.slice(0, 1);
const tokensToTransfer = fungibleTokensToTransfer.concat(nonFungibleTokensToTransfer);
const valuesToTransfer = [new BigNumber(25), new BigNumber(1)];
const valueMultiplier = new BigNumber(1);
const receiverCallbackData = '0x0102030405';
// check balances before transfer
const nftOwnerBalance = new BigNumber(1);
const nftNotOwnerBalance = new BigNumber(0);
const expectedInitialBalances = [
// from
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
nftOwnerBalance,
// to
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
nftNotOwnerBalance,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(1);
const amounts = [valueMultiplier];
const nestedAssetData = [erc1155AssetData];
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
toAddress,
multiAssetAmount,
);
// execute transfer
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
to: multiAssetProxy.address,
data,
from: authorized,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// check balances
const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {
return value.times(valueMultiplier).times(multiAssetAmount);
});
const expectedFinalBalances = [
// from
expectedInitialBalances[0].minus(totalValuesTransferred[0]),
expectedInitialBalances[1].minus(totalValuesTransferred[1]),
// to
expectedInitialBalances[2].plus(totalValuesTransferred[0]),
expectedInitialBalances[3].plus(totalValuesTransferred[1]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should successfully transfer multiple different ERC1155 tokens', async () => {
// setup test parameters
const tokenHolders = [fromAddress, toAddress];
const tokensToTransfer = erc1155FungibleTokens.slice(0, 1);
const valuesToTransfer = [new BigNumber(25)];
const valueMultiplier = new BigNumber(23);
const receiverCallbackData = '0x0102030405';
// check balances before transfer
const expectedInitialBalances = [
// from
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// to
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
await erc1155Wrapper2.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData1 = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
const erc1155AssetData2 = assetDataUtils.encodeERC1155AssetData(
erc1155Contract2.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(5);
const amounts = [valueMultiplier, valueMultiplier];
const nestedAssetData = [erc1155AssetData1, erc1155AssetData2];
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
toAddress,
multiAssetAmount,
);
// execute transfer
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
to: multiAssetProxy.address,
data,
from: authorized,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// check balances
const totalValueTransferred = valuesToTransfer[0].times(valueMultiplier).times(multiAssetAmount);
const expectedFinalBalances = [
// from
expectedInitialBalances[0].minus(totalValueTransferred),
// to
expectedInitialBalances[1].plus(totalValueTransferred),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
await erc1155Wrapper2.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should successfully transfer a combination of ERC20, ERC721, and ERC1155 tokens', async () => {
// setup test parameters
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const erc1155TokenHolders = [fromAddress, toAddress];
const erc1155TokensToTransfer = erc1155FungibleTokens.slice(0, 1);
const erc1155ValuesToTransfer = [new BigNumber(25)];
const erc1155Amount = new BigNumber(23);
const erc1155ReceiverCallbackData = '0x0102030405';
const erc1155AssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
erc1155TokensToTransfer,
erc1155ValuesToTransfer,
erc1155ReceiverCallbackData,
);
const amounts = [erc20Amount, erc721Amount, erc1155Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData, erc1155AssetData];
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
toAddress,
inputAmount,
);
// check balances before transfer
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
expect(ownerFromAsset).to.be.equal(fromAddress);
const erc1155ExpectedInitialBalances = [
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
];
await erc1155Wrapper.assertBalancesAsync(
erc1155TokenHolders,
erc1155TokensToTransfer,
erc1155ExpectedInitialBalances,
);
// execute transfer
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
to: multiAssetProxy.address,
data,
from: authorized,
gas: 1000000,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// check balances after transfer
const newBalances = await erc20Wrapper.getBalancesAsync();
const totalAmount = inputAmount.times(erc20Amount);
expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
);
expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount),
);
const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
expect(newOwnerFromAsset).to.be.equal(toAddress);
const erc1155TotalValueTransferred = erc1155ValuesToTransfer[0].times(erc1155Amount).times(inputAmount);
const expectedFinalBalances = [
erc1155ExpectedInitialBalances[0].minus(erc1155TotalValueTransferred),
erc1155ExpectedInitialBalances[1].plus(erc1155TotalValueTransferred),
];
await erc1155Wrapper.assertBalancesAsync(
erc1155TokenHolders,
erc1155TokensToTransfer,
expectedFinalBalances,
);
});
it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => { it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {
const inputAmount = new BigNumber(1); const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10); const erc20Amount = new BigNumber(10);

View File

@ -1,6 +1,6 @@
[ [
{ {
"version": "0.0.1", "version": "1.0.0",
"changes": [ "changes": [
{ {
"note": "Created Coordinator package" "note": "Created Coordinator package"
@ -12,6 +12,10 @@
{ {
"note": "Add `SignatureType.Invalid`", "note": "Add `SignatureType.Invalid`",
"pr": 1705 "pr": 1705
},
{
"note": "Set `evmVersion` to `constantinople`",
"pr": 1707
} }
] ]
} }

View File

@ -3,7 +3,7 @@
"contractsDir": "./contracts", "contractsDir": "./contracts",
"useDockerisedSolc": true, "useDockerisedSolc": true,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -3,7 +3,7 @@
"contractsDir": "contracts", "contractsDir": "contracts",
"useDockerisedSolc": true, "useDockerisedSolc": true,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "enabled": true, "runs": 1000000 }, "optimizer": { "enabled": true, "runs": 1000000 },
"outputSelection": { "outputSelection": {
"*": { "*": {

View File

@ -2,10 +2,6 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Upgrade contracts to Solidity 0.5.5", "note": "Upgrade contracts to Solidity 0.5.5",
"pr": 1682 "pr": 1682

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -2,10 +2,6 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Upgrade contracts to Solidity 0.5.5", "note": "Upgrade contracts to Solidity 0.5.5",
"pr": 1682 "pr": 1682

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -2,10 +2,6 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Do not reexport external dependencies", "note": "Do not reexport external dependencies",
"pr": 1682 "pr": 1682

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -2,10 +2,6 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Upgrade contracts to Solidity 0.5.5", "note": "Upgrade contracts to Solidity 0.5.5",
"pr": 1682 "pr": 1682

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -2,10 +2,6 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Do not reexport external dependencies", "note": "Do not reexport external dependencies",
"pr": 1682 "pr": 1682
@ -13,6 +9,10 @@
{ {
"note": "Upgrade contracts to Solidity 0.5.5", "note": "Upgrade contracts to Solidity 0.5.5",
"pr": 1682 "pr": 1682
},
{
"note": "Integration testing for ERC1155Proxy",
"pr": 1673
} }
] ]
}, },

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -71,6 +71,7 @@
"@0x/contracts-asset-proxy": "^1.0.9", "@0x/contracts-asset-proxy": "^1.0.9",
"@0x/contracts-erc20": "^1.0.9", "@0x/contracts-erc20": "^1.0.9",
"@0x/contracts-erc721": "^1.0.9", "@0x/contracts-erc721": "^1.0.9",
"@0x/contracts-erc1155": "^1.0.0",
"@0x/contracts-exchange-libs": "^1.1.3", "@0x/contracts-exchange-libs": "^1.1.3",
"@0x/contracts-utils": "^2.0.8", "@0x/contracts-utils": "^2.0.8",
"@0x/order-utils": "^7.0.2", "@0x/order-utils": "^7.0.2",

View File

@ -1,11 +1,13 @@
import { import {
artifacts as proxyArtifacts, artifacts as proxyArtifacts,
ERC1155ProxyWrapper,
ERC20ProxyContract, ERC20ProxyContract,
ERC20Wrapper, ERC20Wrapper,
ERC721ProxyContract, ERC721ProxyContract,
ERC721Wrapper, ERC721Wrapper,
MultiAssetProxyContract, MultiAssetProxyContract,
} from '@0x/contracts-asset-proxy'; } from '@0x/contracts-asset-proxy';
import { ERC1155MintableContract } from '@0x/contracts-erc1155';
import { import {
artifacts as erc20Artifacts, artifacts as erc20Artifacts,
DummyERC20TokenContract, DummyERC20TokenContract,
@ -36,6 +38,7 @@ import { LogWithDecodedArgs } from 'ethereum-types';
import ethUtil = require('ethereumjs-util'); import ethUtil = require('ethereumjs-util');
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Erc1155Wrapper } from '../../erc1155/lib/src';
import { import {
artifacts, artifacts,
ExchangeCancelEventArgs, ExchangeCancelEventArgs,
@ -64,19 +67,26 @@ describe('Exchange core', () => {
let exchange: ExchangeContract; let exchange: ExchangeContract;
let erc20Proxy: ERC20ProxyContract; let erc20Proxy: ERC20ProxyContract;
let erc721Proxy: ERC721ProxyContract; let erc721Proxy: ERC721ProxyContract;
let erc1155Proxy: ERC721ProxyContract;
let multiAssetProxy: MultiAssetProxyContract; let multiAssetProxy: MultiAssetProxyContract;
let maliciousWallet: TestStaticCallReceiverContract; let maliciousWallet: TestStaticCallReceiverContract;
let maliciousValidator: TestStaticCallReceiverContract; let maliciousValidator: TestStaticCallReceiverContract;
let erc1155Contract: ERC1155MintableContract;
let signedOrder: SignedOrder; let signedOrder: SignedOrder;
let erc20Balances: ERC20BalancesByOwner; let erc20Balances: ERC20BalancesByOwner;
let exchangeWrapper: ExchangeWrapper; let exchangeWrapper: ExchangeWrapper;
let erc20Wrapper: ERC20Wrapper; let erc20Wrapper: ERC20Wrapper;
let erc721Wrapper: ERC721Wrapper; let erc721Wrapper: ERC721Wrapper;
let erc1155Wrapper: Erc1155Wrapper;
let erc1155ProxyWrapper: ERC1155ProxyWrapper;
let orderFactory: OrderFactory; let orderFactory: OrderFactory;
let erc721MakerAssetIds: BigNumber[]; let erc721MakerAssetIds: BigNumber[];
let erc721TakerAssetIds: BigNumber[]; let erc721TakerAssetIds: BigNumber[];
let erc1155FungibleTokens: BigNumber[];
let erc1155NonFungibleTokensOwnedByMaker: BigNumber[];
let erc1155NonFungibleTokensOwnedByTaker: BigNumber[];
let defaultMakerAssetAddress: string; let defaultMakerAssetAddress: string;
let defaultTakerAssetAddress: string; let defaultTakerAssetAddress: string;
@ -93,6 +103,7 @@ describe('Exchange core', () => {
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
// Deploy AssetProxies, Exchange, tokens, and malicious contracts // Deploy AssetProxies, Exchange, tokens, and malicious contracts
erc20Proxy = await erc20Wrapper.deployProxyAsync(); erc20Proxy = await erc20Wrapper.deployProxyAsync();
@ -108,6 +119,9 @@ describe('Exchange core', () => {
constants.DUMMY_TOKEN_DECIMALS, constants.DUMMY_TOKEN_DECIMALS,
); );
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
erc1155Contract = erc1155Wrapper.getContract();
exchange = await ExchangeContract.deployFrom0xArtifactAsync( exchange = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange, artifacts.Exchange,
provider, provider,
@ -154,6 +168,20 @@ describe('Exchange core', () => {
constants.AWAIT_TRANSACTION_MINED_MS, constants.AWAIT_TRANSACTION_MINED_MS,
); );
// Configure ERC1155Proxy
await web3Wrapper.awaitTransactionSuccessAsync(
await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Configure MultiAssetProxy // Configure MultiAssetProxy
await web3Wrapper.awaitTransactionSuccessAsync( await web3Wrapper.awaitTransactionSuccessAsync(
await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
@ -178,6 +206,7 @@ describe('Exchange core', () => {
exchangeWrapper = new ExchangeWrapper(exchange, provider); exchangeWrapper = new ExchangeWrapper(exchange, provider);
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner); await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
// Configure ERC20 tokens // Configure ERC20 tokens
@ -189,6 +218,23 @@ describe('Exchange core', () => {
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address]; erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address]; erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
// Configure ERC1155 tokens
await erc1155ProxyWrapper.setBalancesAndAllowancesAsync();
erc1155FungibleTokens = erc1155ProxyWrapper.getFungibleTokenIds();
const nonFungibleTokens = erc1155ProxyWrapper.getNonFungibleTokenIds();
const tokenBalances = await erc1155ProxyWrapper.getBalancesAsync();
erc1155NonFungibleTokensOwnedByMaker = [];
erc1155NonFungibleTokensOwnedByTaker = [];
_.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => {
const nonFungibleTokenAsString = nonFungibleToken.toString();
const nonFungibleTokenHeldByMaker =
tokenBalances.nonFungible[makerAddress][erc1155Contract.address][nonFungibleTokenAsString][0];
erc1155NonFungibleTokensOwnedByMaker.push(nonFungibleTokenHeldByMaker);
const nonFungibleTokenHeldByTaker =
tokenBalances.nonFungible[takerAddress][erc1155Contract.address][nonFungibleTokenAsString][0];
erc1155NonFungibleTokensOwnedByTaker.push(nonFungibleTokenHeldByTaker);
});
// Configure order defaults // Configure order defaults
defaultMakerAssetAddress = erc20TokenA.address; defaultMakerAssetAddress = erc20TokenA.address;
defaultTakerAssetAddress = erc20TokenB.address; defaultTakerAssetAddress = erc20TokenB.address;
@ -1040,6 +1086,435 @@ describe('Exchange core', () => {
); );
}); });
}); });
describe('Testing exchange of erc1155 assets', () => {
it('should allow a single fungible erc1155 asset to be exchanged for another', async () => {
// setup test parameters
const tokenHolders = [makerAddress, takerAddress];
const makerAssetsToTransfer = erc1155FungibleTokens.slice(0, 1);
const takerAssetsToTransfer = erc1155FungibleTokens.slice(1, 2);
const makerValuesToTransfer = [new BigNumber(500)];
const takerValuesToTransfer = [new BigNumber(200)];
const tokensToTransfer = makerAssetsToTransfer.concat(takerAssetsToTransfer);
const makerAssetAmount = new BigNumber(1);
const takerAssetAmount = new BigNumber(1);
const totalMakerValuesTransferred = _.map(makerValuesToTransfer, (value: BigNumber) => {
return value.times(makerAssetAmount);
});
const totalTakerValuesTransferred = _.map(takerValuesToTransfer, (value: BigNumber) => {
return value.times(takerAssetAmount);
});
const receiverCallbackData = '0x';
const makerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
makerAssetsToTransfer,
makerValuesToTransfer,
receiverCallbackData,
);
const takerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
takerAssetsToTransfer,
takerValuesToTransfer,
receiverCallbackData,
);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
takerAssetData,
makerAssetAmount,
takerAssetAmount,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
});
const takerAssetFillAmount = new BigNumber(1);
// check balances before transfer
const expectedInitialBalances = [
// makerAddress / makerToken
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / takerToken
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / takerToken
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// execute transfer
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
});
// check balances after transfer
const expectedFinalBalances = [
// makerAddress / makerToken
expectedInitialBalances[0].minus(totalMakerValuesTransferred[0]),
// makerAddress / takerToken
expectedInitialBalances[1].plus(totalTakerValuesTransferred[0]),
// takerAddress / makerToken
expectedInitialBalances[2].plus(totalMakerValuesTransferred[0]),
// takerAddress / takerToken
expectedInitialBalances[3].minus(totalTakerValuesTransferred[0]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should allow a single non-fungible erc1155 asset to be exchanged for another', async () => {
// setup test parameters
const tokenHolders = [makerAddress, takerAddress];
const makerAssetsToTransfer = erc1155NonFungibleTokensOwnedByMaker.slice(0, 1);
const takerAssetsToTransfer = erc1155NonFungibleTokensOwnedByTaker.slice(0, 1);
const makerValuesToTransfer = [new BigNumber(1)];
const takerValuesToTransfer = [new BigNumber(1)];
const tokensToTransfer = makerAssetsToTransfer.concat(takerAssetsToTransfer);
const makerAssetAmount = new BigNumber(1);
const takerAssetAmount = new BigNumber(1);
const totalMakerValuesTransferred = _.map(makerValuesToTransfer, (value: BigNumber) => {
return value.times(makerAssetAmount);
});
const totalTakerValuesTransferred = _.map(takerValuesToTransfer, (value: BigNumber) => {
return value.times(takerAssetAmount);
});
const receiverCallbackData = '0x';
const makerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
makerAssetsToTransfer,
makerValuesToTransfer,
receiverCallbackData,
);
const takerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
takerAssetsToTransfer,
takerValuesToTransfer,
receiverCallbackData,
);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
takerAssetData,
makerAssetAmount,
takerAssetAmount,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
});
const takerAssetFillAmount = new BigNumber(1);
// check balances before transfer
const nftOwnerBalance = new BigNumber(1);
const nftNotOwnerBalance = new BigNumber(0);
const expectedInitialBalances = [
// makerAddress / makerToken
nftOwnerBalance,
// makerAddress / takerToken
nftNotOwnerBalance,
// takerAddress / makerToken
nftNotOwnerBalance,
// takerAddress / takerToken
nftOwnerBalance,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// execute transfer
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
});
// check balances after transfer
const expectedFinalBalances = [
// makerAddress / makerToken
expectedInitialBalances[0].minus(totalMakerValuesTransferred[0]),
// makerAddress / takerToken
expectedInitialBalances[1].plus(totalTakerValuesTransferred[0]),
// takerAddress / makerToken
expectedInitialBalances[2].plus(totalMakerValuesTransferred[0]),
// takerAddress / takerToken
expectedInitialBalances[3].minus(totalTakerValuesTransferred[0]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should allow multiple erc1155 assets to be exchanged for a single asset', async () => {
// setup test parameters
const tokenHolders = [makerAddress, takerAddress];
const makerAssetsToTransfer = erc1155FungibleTokens.slice(0, 3);
const takerAssetsToTransfer = erc1155NonFungibleTokensOwnedByTaker.slice(0, 1);
const makerValuesToTransfer = [new BigNumber(500), new BigNumber(700), new BigNumber(900)];
const takerValuesToTransfer = [new BigNumber(1)];
const tokensToTransfer = makerAssetsToTransfer.concat(takerAssetsToTransfer);
const makerAssetAmount = new BigNumber(1);
const takerAssetAmount = new BigNumber(1);
const totalMakerValuesTransferred = _.map(makerValuesToTransfer, (value: BigNumber) => {
return value.times(makerAssetAmount);
});
const totalTakerValuesTransferred = _.map(takerValuesToTransfer, (value: BigNumber) => {
return value.times(takerAssetAmount);
});
const receiverCallbackData = '0x';
const makerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
makerAssetsToTransfer,
makerValuesToTransfer,
receiverCallbackData,
);
const takerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
takerAssetsToTransfer,
takerValuesToTransfer,
receiverCallbackData,
);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
takerAssetData,
makerAssetAmount,
takerAssetAmount,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
});
const takerAssetFillAmount = new BigNumber(1);
// check balances before transfer
const nftOwnerBalance = new BigNumber(1);
const nftNotOwnerBalance = new BigNumber(0);
const expectedInitialBalances = [
// makerAddress / makerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / makerToken[1]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / makerToken[2]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / takerToken
nftNotOwnerBalance,
// takerAddress / makerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken[1]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken[2]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / takerToken
nftOwnerBalance,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// execute transfer
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
});
// check balances after transfer
const expectedFinalBalances = [
// makerAddress / makerToken[0]
expectedInitialBalances[0].minus(totalMakerValuesTransferred[0]),
// makerAddress / makerToken[1]
expectedInitialBalances[1].minus(totalMakerValuesTransferred[1]),
// makerAddress / makerToken[2]
expectedInitialBalances[2].minus(totalMakerValuesTransferred[2]),
// makerAddress / takerToken
expectedInitialBalances[3].plus(totalTakerValuesTransferred[0]),
// takerAddress / makerToken[0]
expectedInitialBalances[4].plus(totalMakerValuesTransferred[0]),
// takerAddress / makerToken[1]
expectedInitialBalances[5].plus(totalMakerValuesTransferred[1]),
// takerAddress / makerToken[2]
expectedInitialBalances[6].plus(totalMakerValuesTransferred[2]),
// takerAddress / takerToken
expectedInitialBalances[7].minus(totalTakerValuesTransferred[0]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should allow multiple erc1155 assets to be exchanged for multiple erc1155 assets, mixed fungible/non-fungible', async () => {
// setup test parameters
// the maker is trading two fungibles & one non-fungible
// the taker is trading one fungible & two non-fungibles
const tokenHolders = [makerAddress, takerAddress];
const makerFungibleAssetsToTransfer = erc1155FungibleTokens.slice(0, 2);
const makerNonFungibleAssetsToTransfer = erc1155NonFungibleTokensOwnedByMaker.slice(0, 1);
const makerAssetsToTransfer = makerFungibleAssetsToTransfer.concat(makerNonFungibleAssetsToTransfer);
const takerFungibleAssetsToTransfer = erc1155FungibleTokens.slice(2, 3);
const takerNonFungibleAssetsToTransfer = erc1155NonFungibleTokensOwnedByTaker.slice(0, 2);
const takerAssetsToTransfer = takerFungibleAssetsToTransfer.concat(takerNonFungibleAssetsToTransfer);
const makerValuesToTransfer = [new BigNumber(500), new BigNumber(700), new BigNumber(1)];
const takerValuesToTransfer = [new BigNumber(900), new BigNumber(1), new BigNumber(1)];
const tokensToTransfer = makerAssetsToTransfer.concat(takerAssetsToTransfer);
const makerAssetAmount = new BigNumber(1);
const takerAssetAmount = new BigNumber(1);
const totalMakerValuesTransferred = _.map(makerValuesToTransfer, (value: BigNumber) => {
return value.times(makerAssetAmount);
});
const totalTakerValuesTransferred = _.map(takerValuesToTransfer, (value: BigNumber) => {
return value.times(takerAssetAmount);
});
const receiverCallbackData = '0x';
const makerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
makerAssetsToTransfer,
makerValuesToTransfer,
receiverCallbackData,
);
const takerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
takerAssetsToTransfer,
takerValuesToTransfer,
receiverCallbackData,
);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
takerAssetData,
makerAssetAmount,
takerAssetAmount,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
});
const takerAssetFillAmount = new BigNumber(1);
// check balances before transfer
const nftOwnerBalance = new BigNumber(1);
const nftNotOwnerBalance = new BigNumber(0);
const expectedInitialBalances = [
// makerAddress / makerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / makerToken[1]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / makerToken[2]
nftOwnerBalance,
// makerAddress / takerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / takerToken[1]
nftNotOwnerBalance,
// makerAddress / takerToken[2]
nftNotOwnerBalance,
// takerAddress / makerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken[1]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken[2]
nftNotOwnerBalance,
// takerAddress / takerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / takerToken[1]
nftOwnerBalance,
// takerAddress / takerToken[2]
nftOwnerBalance,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// execute transfer
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
});
// check balances after transfer
const expectedFinalBalances = [
// makerAddress / makerToken[0]
expectedInitialBalances[0].minus(totalMakerValuesTransferred[0]),
// makerAddress / makerToken[1]
expectedInitialBalances[1].minus(totalMakerValuesTransferred[1]),
// makerAddress / makerToken[2]
expectedInitialBalances[2].minus(totalMakerValuesTransferred[2]),
// makerAddress / takerToken[0]
expectedInitialBalances[3].plus(totalTakerValuesTransferred[0]),
// makerAddress / takerToken[1]
expectedInitialBalances[4].plus(totalTakerValuesTransferred[1]),
// makerAddress / takerToken[2]
expectedInitialBalances[5].plus(totalTakerValuesTransferred[2]),
// takerAddress / makerToken[0]
expectedInitialBalances[6].plus(totalMakerValuesTransferred[0]),
// takerAddress / makerToken[1]
expectedInitialBalances[7].plus(totalMakerValuesTransferred[1]),
// takerAddress / makerToken[2]
expectedInitialBalances[8].plus(totalMakerValuesTransferred[2]),
// takerAddress / takerToken[0]
expectedInitialBalances[9].minus(totalTakerValuesTransferred[0]),
// takerAddress / takerToken[1]
expectedInitialBalances[10].minus(totalTakerValuesTransferred[1]),
// takerAddress / takerToken[2]
expectedInitialBalances[11].minus(totalTakerValuesTransferred[2]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should allow an order exchanging erc1155 assets to be partially filled', async () => {
// NOTICE:
// As-per the eip1155 standard, there is no way to distinguish between a fungible or non-fungible erc1155 assets.
// Hence we cannot force partial fills to fail if there is a non-fungible asset (which should be fill or kill).
// We considered encoding whether an asset is fungible/non-fungible in erc1155 assetData, but
// this is no more robust than a simple check by the client. Enforcing this at the smart contract level
// is something that could be done with the upcoming static call proxy.
//
// setup test parameters
// the maker is trading two fungibles and the taker is trading one fungible
// note that this will result in a partial fill because the `takerAssetAmount`
// less than the `takerAssetAmount` of the order.
const takerAssetFillAmount = new BigNumber(6);
const tokenHolders = [makerAddress, takerAddress];
const makerAssetsToTransfer = erc1155FungibleTokens.slice(0, 2);
const takerAssetsToTransfer = erc1155FungibleTokens.slice(2, 3);
const makerValuesToTransfer = [new BigNumber(500), new BigNumber(700)];
const takerValuesToTransfer = [new BigNumber(900)];
const tokensToTransfer = makerAssetsToTransfer.concat(takerAssetsToTransfer);
const makerAssetAmount = new BigNumber(10);
const takerAssetAmount = new BigNumber(20);
const totalMakerValuesTransferred = _.map(makerValuesToTransfer, (value: BigNumber) => {
return value
.times(makerAssetAmount)
.times(takerAssetFillAmount)
.dividedToIntegerBy(takerAssetAmount);
});
const totalTakerValuesTransferred = _.map(takerValuesToTransfer, (value: BigNumber) => {
return value
.times(takerAssetAmount)
.times(takerAssetFillAmount)
.dividedToIntegerBy(takerAssetAmount);
});
const receiverCallbackData = '0x';
const makerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
makerAssetsToTransfer,
makerValuesToTransfer,
receiverCallbackData,
);
const takerAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155Contract.address,
takerAssetsToTransfer,
takerValuesToTransfer,
receiverCallbackData,
);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
takerAssetData,
makerAssetAmount,
takerAssetAmount,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
});
// check balances before transfer
const expectedInitialBalances = [
// makerAddress / makerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / makerToken[1]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// makerAddress / takerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / makerToken[1]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
// takerAddress / takerToken[0]
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// execute transfer
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
});
// check balances after transfer
const expectedFinalBalances = [
// makerAddress / makerToken[0]
expectedInitialBalances[0].minus(totalMakerValuesTransferred[0]),
// makerAddress / makerToken[1]
expectedInitialBalances[1].minus(totalMakerValuesTransferred[1]),
// makerAddress / takerToken[0]
expectedInitialBalances[2].plus(totalTakerValuesTransferred[0]),
// takerAddress / makerToken[0]
expectedInitialBalances[3].plus(totalMakerValuesTransferred[0]),
// takerAddress / makerToken[1]
expectedInitialBalances[4].plus(totalMakerValuesTransferred[1]),
// takerAddress / takerToken[0]
expectedInitialBalances[5].minus(totalTakerValuesTransferred[0]),
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
// check that the order is partially filled
const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
const expectedTakerAssetFilledAmount = takerAssetFillAmount;
const expectedOrderStatus = OrderStatus.Fillable;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
});
describe('getOrderInfo', () => { describe('getOrderInfo', () => {
beforeEach(async () => { beforeEach(async () => {

View File

@ -1,3 +1,4 @@
import { artifacts as erc1155Artifacts } from '@0x/contracts-erc1155';
import { artifacts as erc20Artifacts } from '@0x/contracts-erc20'; import { artifacts as erc20Artifacts } from '@0x/contracts-erc20';
import { artifacts as erc721Artifacts } from '@0x/contracts-erc721'; import { artifacts as erc721Artifacts } from '@0x/contracts-erc721';
import { import {
@ -25,7 +26,12 @@ export class ExchangeWrapper {
constructor(exchangeContract: ExchangeContract, provider: Web3ProviderEngine | ZeroExProvider) { constructor(exchangeContract: ExchangeContract, provider: Web3ProviderEngine | ZeroExProvider) {
this._exchange = exchangeContract; this._exchange = exchangeContract;
this._web3Wrapper = new Web3Wrapper(provider); this._web3Wrapper = new Web3Wrapper(provider);
this._logDecoder = new LogDecoder(this._web3Wrapper, { ...artifacts, ...erc20Artifacts, ...erc721Artifacts }); this._logDecoder = new LogDecoder(this._web3Wrapper, {
...artifacts,
...erc20Artifacts,
...erc721Artifacts,
...erc1155Artifacts,
});
} }
public async fillOrderAsync( public async fillOrderAsync(
signedOrder: SignedOrder, signedOrder: SignedOrder,

View File

@ -2,10 +2,6 @@
{ {
"version": "3.0.0", "version": "3.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Do not reexport external dependencies", "note": "Do not reexport external dependencies",
"pr": 1682 "pr": 1682

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -2,10 +2,6 @@
{ {
"version": "3.0.0", "version": "3.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Do not reexport external dependencies", "note": "Do not reexport external dependencies",
"pr": 1682 "pr": 1682

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -38,7 +38,7 @@ export const constants = {
NUM_DUMMY_ERC20_TO_DEPLOY: 3, NUM_DUMMY_ERC20_TO_DEPLOY: 3,
NUM_DUMMY_ERC721_TO_DEPLOY: 2, NUM_DUMMY_ERC721_TO_DEPLOY: 2,
NUM_ERC721_TOKENS_TO_MINT: 2, NUM_ERC721_TOKENS_TO_MINT: 2,
NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY: 1, NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY: 2,
NUM_ERC1155_FUNGIBLE_TOKENS_MINT: 3, NUM_ERC1155_FUNGIBLE_TOKENS_MINT: 3,
NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT: 3, NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT: 3,
NULL_ADDRESS: '0x0000000000000000000000000000000000000000', NULL_ADDRESS: '0x0000000000000000000000000000000000000000',

View File

@ -2,10 +2,6 @@
{ {
"version": "3.0.0", "version": "3.0.0",
"changes": [ "changes": [
{
"note": "Set evmVersion to byzantium",
"pr": 1678
},
{ {
"note": "Optimize loops in LibAddressArray", "note": "Optimize loops in LibAddressArray",
"pr": 1668 "pr": 1668

View File

@ -4,7 +4,7 @@
"useDockerisedSolc": true, "useDockerisedSolc": true,
"isOfflineMode": false, "isOfflineMode": false,
"compilerSettings": { "compilerSettings": {
"evmVersion": "byzantium", "evmVersion": "constantinople",
"optimizer": { "optimizer": {
"enabled": true, "enabled": true,
"runs": 1000000, "runs": 1000000,

View File

@ -5,6 +5,10 @@
{ {
"note": "Add addresses for coordinator extension contract and coordinator registry", "note": "Add addresses for coordinator extension contract and coordinator registry",
"pr": 1689 "pr": 1689
},
{
"note": "Added Dutch Auction mainnet address",
"pr": 1715
} }
] ]
}, },

View File

@ -34,8 +34,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
assetProxyOwner: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6', assetProxyOwner: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6',
forwarder: '0x5468a1dc173652ee28d249c271fa9933144746b1', forwarder: '0x5468a1dc173652ee28d249c271fa9933144746b1',
orderValidator: '0x9463e518dea6810309563c81d5266c1b1d149138', orderValidator: '0x9463e518dea6810309563c81d5266c1b1d149138',
// @todo hysz/dekz: Add mainnet address once deployed. dutchAuction: '0x07b32a653754945666cfca91168bb207323dfe67',
dutchAuction: NULL_ADDRESS,
coordinatorRegistry: '0x45797531b873fd5e519477a070a955764c1a5b07', coordinatorRegistry: '0x45797531b873fd5e519477a070a955764c1a5b07',
coordinator: '0x24675738816c87ad37e712cc24f309a0c906187f', coordinator: '0x24675738816c87ad37e712cc24f309a0c906187f',
}, },

View File

@ -1,6 +1,6 @@
import * as chai from 'chai'; import * as chai from 'chai';
import { AssetProxyId, ERC721AssetData } from '@0x/types'; import { AssetProxyId, ERC1155AssetData, 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';
@ -30,10 +30,14 @@ const KNOWN_ERC1155_ENCODING = {
'0x9645780d0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', '0x9645780d0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
}; };
const KNOWN_MULTI_ASSET_ENCODING = { const KNOWN_MULTI_ASSET_ENCODING = {
amounts: [new BigNumber(1), new BigNumber(1)], amounts: [new BigNumber(70), new BigNumber(1), new BigNumber(18)],
nestedAssetData: [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData], nestedAssetData: [
KNOWN_ERC20_ENCODING.assetData,
KNOWN_ERC721_ENCODING.assetData,
KNOWN_ERC1155_ENCODING.assetData,
],
assetData: assetData:
'0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002049645780d0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
}; };
describe('assetDataUtils', () => { describe('assetDataUtils', () => {
@ -76,14 +80,14 @@ describe('assetDataUtils', () => {
expect(decodedAssetData.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); expect(decodedAssetData.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds);
expect(decodedAssetData.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); expect(decodedAssetData.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData);
}); });
it('should encode ERC20 and ERC721 multiAssetData', () => { it('should encode ERC20, ERC721 and ERC1155 multiAssetData', () => {
const assetData = assetDataUtils.encodeMultiAssetData( const assetData = assetDataUtils.encodeMultiAssetData(
KNOWN_MULTI_ASSET_ENCODING.amounts, KNOWN_MULTI_ASSET_ENCODING.amounts,
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData, KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
); );
expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData); expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
}); });
it('should decode ERC20 and ERC721 multiAssetData', () => { it('should decode ERC20, ERC721 and ERC1155 multiAssetData', () => {
const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData); const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData);
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts); expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
@ -93,44 +97,79 @@ describe('assetDataUtils', () => {
const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(KNOWN_MULTI_ASSET_ENCODING.assetData); const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(KNOWN_MULTI_ASSET_ENCODING.assetData);
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts); expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
expect(decodedAssetData.nestedAssetData.length).to.equal(3);
const decodedErc20AssetData = decodedAssetData.nestedAssetData[0]; 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.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20); expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
// tslint:disable-next-line:no-unnecessary-type-assertion
const decodedErc721AssetData = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
expect(decodedErc721AssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); expect(decodedErc721AssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
expect(decodedErc721AssetData.assetProxyId).to.equal(AssetProxyId.ERC721); expect(decodedErc721AssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
expect(decodedErc721AssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); expect(decodedErc721AssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
// tslint:disable-next-line:no-unnecessary-type-assertion
const decodedErc1155AssetData = decodedAssetData.nestedAssetData[2] as ERC1155AssetData;
expect(decodedErc1155AssetData.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress);
expect(decodedErc1155AssetData.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues);
expect(decodedErc1155AssetData.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds);
expect(decodedErc1155AssetData.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData);
}); });
it('should recursively decode nested assetData within multiAssetData', () => { it('should recursively decode nested assetData within multiAssetData', () => {
const amounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2)]; // setup test parameters
const erc20Amount = new BigNumber(1);
const erc721Amount = new BigNumber(1);
const erc1155Amount = new BigNumber(15);
const nestedAssetsAmount = new BigNumber(2);
const amounts = [erc20Amount, erc721Amount, erc1155Amount, nestedAssetsAmount];
const nestedAssetData = [ const nestedAssetData = [
KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC20_ENCODING.assetData,
KNOWN_ERC721_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData,
KNOWN_ERC1155_ENCODING.assetData,
KNOWN_MULTI_ASSET_ENCODING.assetData, KNOWN_MULTI_ASSET_ENCODING.assetData,
]; ];
const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData); const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
// execute test
const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(assetData); const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(assetData);
// validate asset data
expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
const expectedAmounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2), new BigNumber(2)]; const expectedAmounts = [
erc20Amount,
erc721Amount,
erc1155Amount,
KNOWN_MULTI_ASSET_ENCODING.amounts[0].times(nestedAssetsAmount),
KNOWN_MULTI_ASSET_ENCODING.amounts[1].times(nestedAssetsAmount),
KNOWN_MULTI_ASSET_ENCODING.amounts[2].times(nestedAssetsAmount),
];
expect(decodedAssetData.amounts).to.deep.equal(expectedAmounts); expect(decodedAssetData.amounts).to.deep.equal(expectedAmounts);
const expectedLength = 4; const expectedNestedAssetDataLength = 6;
expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedLength); expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedNestedAssetDataLength);
const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[0]; // validate nested asset data (outer)
// tslint:disable-next-line:no-unnecessary-type-assertion let nestedAssetDataIndex = 0;
const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[1] as ERC721AssetData; const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++];
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.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20); expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20);
// tslint:disable-next-line:no-unnecessary-type-assertion
const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC721AssetData;
expect(decodedErc721AssetData1.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); expect(decodedErc721AssetData1.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
expect(decodedErc721AssetData1.assetProxyId).to.equal(AssetProxyId.ERC721); expect(decodedErc721AssetData1.assetProxyId).to.equal(AssetProxyId.ERC721);
expect(decodedErc721AssetData1.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); // tslint:disable-next-line:no-unnecessary-type-assertion
const decodedErc1155AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC1155AssetData;
expect(decodedErc1155AssetData1.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress);
expect(decodedErc1155AssetData1.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues);
expect(decodedErc1155AssetData1.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds);
expect(decodedErc1155AssetData1.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData);
// validate nested asset data (inner)
const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++];
expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20); expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20);
// tslint:disable-next-line:no-unnecessary-type-assertion
const decodedErc721AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC721AssetData;
expect(decodedErc721AssetData2.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); expect(decodedErc721AssetData2.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
expect(decodedErc721AssetData2.assetProxyId).to.equal(AssetProxyId.ERC721); expect(decodedErc721AssetData2.assetProxyId).to.equal(AssetProxyId.ERC721);
expect(decodedErc721AssetData2.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); // tslint:disable-next-line:no-unnecessary-type-assertion
const decodedErc1155AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC1155AssetData;
expect(decodedErc1155AssetData2.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress);
expect(decodedErc1155AssetData2.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues);
expect(decodedErc1155AssetData2.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds);
expect(decodedErc1155AssetData2.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData);
}); });
}); });

View File

@ -9,6 +9,10 @@
{ {
"note": "Fix issue where ERC721 Approval events could cause a lookup on undefined object", "note": "Fix issue where ERC721 Approval events could cause a lookup on undefined object",
"pr": 1692 "pr": 1692
},
{
"note": "Fix race-condition bugs due to async event callbacks modifying shared state",
"pr": 1718
} }
] ]
}, },

View File

@ -81,6 +81,7 @@
"ethereumjs-blockstream": "6.0.0", "ethereumjs-blockstream": "6.0.0",
"ethers": "~4.0.4", "ethers": "~4.0.4",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"semaphore-async-await": "^1.5.1",
"websocket": "^1.0.26" "websocket": "^1.0.26"
}, },
"publishConfig": { "publishConfig": {

View File

@ -42,6 +42,7 @@ import {
ZeroExProvider, ZeroExProvider,
} from 'ethereum-types'; } from 'ethereum-types';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Lock } from 'semaphore-async-await';
import { orderWatcherPartialConfigSchema } from '../schemas/order_watcher_partial_config_schema'; import { orderWatcherPartialConfigSchema } from '../schemas/order_watcher_partial_config_schema';
import { OnOrderStateChangeCallback, OrderWatcherConfig, OrderWatcherError } from '../types'; import { OnOrderStateChangeCallback, OrderWatcherConfig, OrderWatcherError } from '../types';
@ -84,6 +85,7 @@ export class OrderWatcher {
private readonly _dependentOrderHashesTracker: DependentOrderHashesTracker; private readonly _dependentOrderHashesTracker: DependentOrderHashesTracker;
private readonly _orderStateByOrderHashCache: OrderStateByOrderHash = {}; private readonly _orderStateByOrderHashCache: OrderStateByOrderHash = {};
private readonly _orderByOrderHash: OrderByOrderHash = {}; private readonly _orderByOrderHash: OrderByOrderHash = {};
private readonly _lock = new Lock();
private readonly _eventWatcher: EventWatcher; private readonly _eventWatcher: EventWatcher;
private readonly _provider: ZeroExProvider; private readonly _provider: ZeroExProvider;
private readonly _collisionResistantAbiDecoder: CollisionResistanceAbiDecoder; private readonly _collisionResistantAbiDecoder: CollisionResistanceAbiDecoder;
@ -196,10 +198,12 @@ export class OrderWatcher {
throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); throw new Error(OrderWatcherError.SubscriptionAlreadyPresent);
} }
this._callbackIfExists = callback; this._callbackIfExists = callback;
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this)); this._eventWatcher.subscribe(
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this)); this._addLockToCallbackAsync.bind(this, this._onEventWatcherCallbackAsync.bind(this)),
);
this._expirationWatcher.subscribe(this._addLockToCallbackAsync.bind(this, this._onOrderExpired.bind(this)));
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this._cleanupAsync.bind(this), this._addLockToCallbackAsync.bind(this, this._cleanupAsync.bind(this)),
this._cleanupJobInterval, this._cleanupJobInterval,
(err: Error) => { (err: Error) => {
this.unsubscribe(); this.unsubscribe();
@ -229,6 +233,17 @@ export class OrderWatcher {
orderCount: _.size(this._orderByOrderHash), orderCount: _.size(this._orderByOrderHash),
}; };
} }
private async _addLockToCallbackAsync(cbAsync: any, ...params: any[]): Promise<void> {
await this._lock.acquire();
try {
await cbAsync(...params);
await this._lock.release();
} catch (err) {
// Make sure to releasee the lock if an error is thrown
await this._lock.release();
throw err;
}
}
private async _cleanupAsync(): Promise<void> { private async _cleanupAsync(): Promise<void> {
for (const orderHash of _.keys(this._orderByOrderHash)) { for (const orderHash of _.keys(this._orderByOrderHash)) {
this._cleanupOrderRelatedState(orderHash); this._cleanupOrderRelatedState(orderHash);
@ -493,4 +508,4 @@ export class OrderWatcher {
this._callbackIfExists(null, orderState); this._callbackIfExists(null, orderState);
} }
} }
} } // tslint:disable:max-file-line-count

View File

@ -175,10 +175,14 @@ describe('OrderWatcher', () => {
}); });
}); });
describe('tests with cleanup', async () => { describe('tests with cleanup', async () => {
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => { afterEach(async () => {
orderWatcher.unsubscribe(); orderWatcher.unsubscribe();
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
orderWatcher.removeOrder(orderHash); orderWatcher.removeOrder(orderHash);
await blockchainLifecycle.revertAsync();
}); });
it('should emit orderStateInvalid when makerAddress allowance set to 0 for watched order', (done: DoneCallback) => { it('should emit orderStateInvalid when makerAddress allowance set to 0 for watched order', (done: DoneCallback) => {
(async () => { (async () => {

View File

@ -1,4 +1,13 @@
[ [
{
"version": "4.0.3",
"changes": [
{
"note": "Update ganache-core to 2.5.3",
"pr": 1707
}
]
},
{ {
"timestamp": 1551479279, "timestamp": 1551479279,
"version": "4.0.2", "version": "4.0.2",

View File

@ -45,7 +45,7 @@
"ethereum-types": "^2.1.0", "ethereum-types": "^2.1.0",
"ethereumjs-tx": "^1.3.5", "ethereumjs-tx": "^1.3.5",
"ethereumjs-util": "^5.1.1", "ethereumjs-util": "^5.1.1",
"ganache-core": "^2.3.3", "ganache-core": "^2.5.3",
"hdkey": "^0.7.1", "hdkey": "^0.7.1",
"json-rpc-error": "2.0.0", "json-rpc-error": "2.0.0",
"lodash": "^4.17.11", "lodash": "^4.17.11",

View File

@ -1,4 +1,13 @@
[ [
{
"version": "6.0.3",
"changes": [
{
"note": "Update ganache-core to 2.5.3",
"pr": 1707
}
]
},
{ {
"timestamp": 1551479279, "timestamp": 1551479279,
"version": "6.0.2", "version": "6.0.2",

View File

@ -42,7 +42,7 @@
"chai-as-promised": "^7.1.0", "chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0", "chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"ganache-core": "^2.3.3", "ganache-core": "^2.5.3",
"make-promises-safe": "^1.1.0", "make-promises-safe": "^1.1.0",
"mocha": "^4.1.0", "mocha": "^4.1.0",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",

View File

@ -35,7 +35,7 @@ describe('Web3Wrapper tests', () => {
describe('#getNodeVersionAsync', () => { describe('#getNodeVersionAsync', () => {
it('gets the node version', async () => { it('gets the node version', async () => {
const nodeVersion = await web3Wrapper.getNodeVersionAsync(); const nodeVersion = await web3Wrapper.getNodeVersionAsync();
const NODE_VERSION = 'EthereumJS TestRPC/v2.3.3/ethereum-js'; const NODE_VERSION = 'EthereumJS TestRPC/v2.5.3/ethereum-js';
expect(nodeVersion).to.be.equal(NODE_VERSION); expect(nodeVersion).to.be.equal(NODE_VERSION);
}); });
}); });

View File

@ -8,10 +8,10 @@ In order to use `CoverageSubprovider` with your favorite framework you need to p
### Sol-compiler ### Sol-compiler
If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactAdapter` we've implemented for you.
```typescript ```typescript
import { SolCompilerArtifactsAdapter } from '@0x/sol-coverage'; import { SolCompilerArtifactAdapter } from '@0x/sol-coverage';
// Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in // Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in
const artifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir); const artifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir);
``` ```

View File

@ -8,10 +8,10 @@ In order to use `ProfilerSubprovider` with your favorite framework you need to p
### Sol-compiler ### Sol-compiler
If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactAdapter` we've implemented for you.
```typescript ```typescript
import { SolCompilerArtifactsAdapter } from '@0x/sol-profiler'; import { SolCompilerArtifactAdapter } from '@0x/sol-profiler';
// Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in // Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in
const artifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir); const artifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir);
``` ```

View File

@ -8,10 +8,10 @@ In order to use `RevertTraceSubprovider` with your favorite framework you need t
### Sol-compiler ### Sol-compiler
If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactAdapter` we've implemented for you.
```typescript ```typescript
import { SolCompilerArtifactsAdapter } from '@0x/sol-trace'; import { SolCompilerArtifactAdapter } from '@0x/sol-trace';
// Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in // Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in
const artifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir); const artifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir);
``` ```

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -158,6 +158,11 @@ const team: TeamMember[] = [
name: 'Marc Savino', name: 'Marc Savino',
title: 'technical sourcer', title: 'technical sourcer',
}, },
{
imageUrl: '/images/team/danielp.png',
name: 'Daniel Pyrathon',
title: 'engineer',
},
]; ];
const advisors: TeamMember[] = [ const advisors: TeamMember[] = [

123
yarn.lock
View File

@ -6495,6 +6495,16 @@ ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0, ether
ethereumjs-util "^5.0.0" ethereumjs-util "^5.0.0"
merkle-patricia-tree "^2.1.2" merkle-patricia-tree "^2.1.2"
ethereumjs-block@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.0.tgz#8c6c3ab4a5eff0a16d9785fbeedbe643f4dbcbef"
dependencies:
async "^2.0.1"
ethereumjs-common "^1.1.0"
ethereumjs-tx "^1.2.2"
ethereumjs-util "^5.0.0"
merkle-patricia-tree "^2.1.2"
ethereumjs-blockstream@6.0.0: ethereumjs-blockstream@6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/ethereumjs-blockstream/-/ethereumjs-blockstream-6.0.0.tgz#79d726d1f358935eb65195e91d40344c31e87eff" resolved "https://registry.yarnpkg.com/ethereumjs-blockstream/-/ethereumjs-blockstream-6.0.0.tgz#79d726d1f358935eb65195e91d40344c31e87eff"
@ -6507,9 +6517,9 @@ ethereumjs-common@^0.6.0:
version "0.6.1" version "0.6.1"
resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-0.6.1.tgz#ec98edf315a7f107afb6acc48e937a8266979fae" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-0.6.1.tgz#ec98edf315a7f107afb6acc48e937a8266979fae"
ethereumjs-common@~0.4.0: ethereumjs-common@^1.1.0:
version "0.4.1" version "1.1.0"
resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-0.4.1.tgz#27690a24a817b058cc3a2aedef9392e8d7d63984" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.1.0.tgz#5ec9086c314d619d8f05e79a0525829fcb0e93cb"
ethereumjs-tx@1.3.7: ethereumjs-tx@1.3.7:
version "1.3.7" version "1.3.7"
@ -6559,21 +6569,17 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
secp256k1 "^3.0.1" secp256k1 "^3.0.1"
ethereumjs-vm@2.4.0: ethereumjs-util@^6.0.0:
version "2.4.0" version "6.1.0"
resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.4.0.tgz#244f1e35f2755e537a13546111d1a4c159d34b13" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz#e9c51e5549e8ebd757a339cc00f5380507e799c8"
dependencies: dependencies:
async "^2.1.2" bn.js "^4.11.0"
async-eventemitter "^0.2.2" create-hash "^1.1.2"
ethereumjs-account "^2.0.3" ethjs-util "0.1.6"
ethereumjs-block "~1.7.0" keccak "^1.0.2"
ethereumjs-common "~0.4.0" rlp "^2.0.0"
ethereumjs-util "^5.2.0"
fake-merkle-patricia-tree "^1.0.1"
functional-red-black-tree "^1.0.1"
merkle-patricia-tree "^2.1.2"
rustbn.js "~0.2.0"
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
secp256k1 "^3.0.1"
ethereumjs-vm@^2.0.2, ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4: ethereumjs-vm@^2.0.2, ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4:
version "2.3.4" version "2.3.4"
@ -6591,6 +6597,22 @@ ethereumjs-vm@^2.0.2, ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4:
rustbn.js "~0.1.1" rustbn.js "~0.1.1"
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
ethereumjs-vm@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6"
dependencies:
async "^2.1.2"
async-eventemitter "^0.2.2"
ethereumjs-account "^2.0.3"
ethereumjs-block "~2.2.0"
ethereumjs-common "^1.1.0"
ethereumjs-util "^6.0.0"
fake-merkle-patricia-tree "^1.0.1"
functional-red-black-tree "^1.0.1"
merkle-patricia-tree "^2.3.2"
rustbn.js "~0.2.0"
safe-buffer "^5.1.1"
ethereumjs-wallet@0.6.2: ethereumjs-wallet@0.6.2:
version "0.6.2" version "0.6.2"
resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda" resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda"
@ -6642,6 +6664,13 @@ ethjs-unit@0.1.6:
bn.js "4.11.6" bn.js "4.11.6"
number-to-bn "1.7.0" number-to-bn "1.7.0"
ethjs-util@0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536"
dependencies:
is-hex-prefixed "1.0.0"
strip-hex-prefix "1.0.0"
ethjs-util@^0.1.3: ethjs-util@^0.1.3:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.4.tgz#1c8b6879257444ef4d3f3fbbac2ded12cd997d93" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.4.tgz#1c8b6879257444ef4d3f3fbbac2ded12cd997d93"
@ -7506,9 +7535,9 @@ ganache-cli@6.4.1:
source-map-support "0.5.9" source-map-support "0.5.9"
yargs "11.1.0" yargs "11.1.0"
ganache-core@^2.3.3: ganache-core@^2.5.3:
version "2.3.3" version "2.5.3"
resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.3.3.tgz#e35c76d405f0ffba5c48621596fdcc38b0a03136" resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.5.3.tgz#8c6f21d820a694826082dfbb2dc59f834a6874fc"
dependencies: dependencies:
abstract-leveldown "3.0.0" abstract-leveldown "3.0.0"
async "2.6.1" async "2.6.1"
@ -7524,11 +7553,11 @@ ganache-core@^2.3.3:
ethereumjs-block "2.1.0" ethereumjs-block "2.1.0"
ethereumjs-tx "1.3.7" ethereumjs-tx "1.3.7"
ethereumjs-util "5.2.0" ethereumjs-util "5.2.0"
ethereumjs-vm "2.4.0" ethereumjs-vm "^2.6.0"
heap "0.2.6" heap "0.2.6"
level-sublevel "6.6.4" level-sublevel "6.6.4"
levelup "3.1.1" levelup "3.1.1"
lodash "4.17.10" lodash "4.17.11"
merkle-patricia-tree "2.3.1" merkle-patricia-tree "2.3.1"
rlp "2.1.0" rlp "2.1.0"
seedrandom "2.4.4" seedrandom "2.4.4"
@ -10627,9 +10656,9 @@ lodash.words@^3.0.0:
dependencies: dependencies:
lodash._root "^3.0.0" lodash._root "^3.0.0"
lodash@4.17.10, lodash@^4.17.10: lodash@4.17.11, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.3:
version "4.17.10" version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
lodash@=4.17.4: lodash@=4.17.4:
version "4.17.4" version "4.17.4"
@ -10639,14 +10668,14 @@ lodash@^3.3.1, lodash@^3.6.0, lodash@^3.7.0:
version "3.10.1" version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.3:
version "4.17.11"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
lodash@^4.14.0, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1: lodash@^4.14.0, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1:
version "4.17.5" version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
lodash@^4.17.10:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
lodash@~1.0.1: lodash@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
@ -11046,6 +11075,19 @@ merkle-patricia-tree@2.3.1, merkle-patricia-tree@^2.1.2:
rlp "^2.0.0" rlp "^2.0.0"
semaphore ">=1.0.1" semaphore ">=1.0.1"
merkle-patricia-tree@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a"
dependencies:
async "^1.4.2"
ethereumjs-util "^5.0.0"
level-ws "0.0.0"
levelup "^1.2.1"
memdown "^1.0.0"
readable-stream "^2.0.0"
rlp "^2.0.0"
semaphore ">=1.0.1"
methods@~1.1.2: methods@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@ -13506,6 +13548,15 @@ react-dom@^16.3.2:
object-assign "^4.1.1" object-assign "^4.1.1"
prop-types "^15.6.0" prop-types "^15.6.0"
react-dom@^16.4.2:
version "16.8.4"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.4.tgz#1061a8e01a2b3b0c8160037441c3bf00a0e3bc48"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.13.4"
react-dom@^16.5.2: react-dom@^16.5.2:
version "16.5.2" version "16.5.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.5.2.tgz#b69ee47aa20bab5327b2b9d7c1fe2a30f2cfa9d7" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.5.2.tgz#b69ee47aa20bab5327b2b9d7c1fe2a30f2cfa9d7"
@ -13809,6 +13860,15 @@ react@^16.3.2:
object-assign "^4.1.1" object-assign "^4.1.1"
prop-types "^15.6.0" prop-types "^15.6.0"
react@^16.4.2:
version "16.8.4"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.4.tgz#fdf7bd9ae53f03a9c4cd1a371432c206be1c4768"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.13.4"
react@^16.5.2: react@^16.5.2:
version "16.5.2" version "16.5.2"
resolved "https://registry.yarnpkg.com/react/-/react-16.5.2.tgz#19f6b444ed139baa45609eee6dc3d318b3895d42" resolved "https://registry.yarnpkg.com/react/-/react-16.5.2.tgz#19f6b444ed139baa45609eee6dc3d318b3895d42"
@ -14680,6 +14740,13 @@ schedule@^0.5.0:
dependencies: dependencies:
object-assign "^4.1.1" object-assign "^4.1.1"
scheduler@^0.13.4:
version "0.13.4"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.4.tgz#8fef05e7a3580c76c0364d2df5e550e4c9140298"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
schema-utils@^0.4.4: schema-utils@^0.4.4:
version "0.4.7" version "0.4.7"
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"