Add StaticCallProxy support to LibAssetData
This commit is contained in:
parent
f2cbf4a561
commit
5810e7df82
@ -43,6 +43,9 @@ contract LibAssetData is
|
|||||||
bytes4 constant internal _ERC1155_BALANCE_OF_SELECTOR = 0x00fdd58e;
|
bytes4 constant internal _ERC1155_BALANCE_OF_SELECTOR = 0x00fdd58e;
|
||||||
bytes4 constant internal _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
|
bytes4 constant internal _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
|
||||||
|
|
||||||
|
// `transferFrom` selector for all AssetProxy contracts
|
||||||
|
bytes4 constant internal _ASSET_PROXY_TRANSFER_FROM_SELECTOR = 0xa85e59e4;
|
||||||
|
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
|
|
||||||
// solhint-disable var-name-mixedcase
|
// solhint-disable var-name-mixedcase
|
||||||
@ -50,6 +53,7 @@ contract LibAssetData is
|
|||||||
address internal _ERC20_PROXY_ADDRESS;
|
address internal _ERC20_PROXY_ADDRESS;
|
||||||
address internal _ERC721_PROXY_ADDRESS;
|
address internal _ERC721_PROXY_ADDRESS;
|
||||||
address internal _ERC1155_PROXY_ADDRESS;
|
address internal _ERC1155_PROXY_ADDRESS;
|
||||||
|
address internal _STATIC_CALL_PROXY_ADDRESS;
|
||||||
// solhint-enable var-name-mixedcase
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
constructor (address _exchange)
|
constructor (address _exchange)
|
||||||
@ -59,6 +63,7 @@ contract LibAssetData is
|
|||||||
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||||
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID);
|
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID);
|
||||||
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID);
|
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID);
|
||||||
|
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(STATIC_CALL_PROXY_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Returns the owner's balance of the assets(s) specified in
|
/// @dev Returns the owner's balance of the assets(s) specified in
|
||||||
@ -115,6 +120,21 @@ contract LibAssetData is
|
|||||||
balance = scaledBalance;
|
balance = scaledBalance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (assetProxyId == STATIC_CALL_PROXY_ID) {
|
||||||
|
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
|
||||||
|
bytes memory transferFromData = abi.encodeWithSelector(
|
||||||
|
_ASSET_PROXY_TRANSFER_FROM_SELECTOR,
|
||||||
|
assetData,
|
||||||
|
address(0), // `from` address is not used
|
||||||
|
address(0), // `to` address is not used
|
||||||
|
0 // `amount` is not used
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if staticcall would be successful
|
||||||
|
(bool success,) = _STATIC_CALL_PROXY_ADDRESS.staticcall(transferFromData);
|
||||||
|
|
||||||
|
// Success means that the staticcall can be made an unlimited amount of times
|
||||||
|
balance = success ? _MAX_UINT256 : 0;
|
||||||
} else if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
} else if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||||
// Get array of values and array of assetDatas
|
// Get array of values and array of assetDatas
|
||||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||||
@ -241,6 +261,9 @@ contract LibAssetData is
|
|||||||
// Query allowance
|
// Query allowance
|
||||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
||||||
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
||||||
|
} else if (assetProxyId == STATIC_CALL_PROXY_ID) {
|
||||||
|
// The StaticCallProxy does not require any approvals
|
||||||
|
allowance = _MAX_UINT256;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allowance will be 0 if the assetProxyId is unknown
|
// Allowance will be 0 if the assetProxyId is unknown
|
||||||
|
@ -7,6 +7,8 @@ import {
|
|||||||
ERC20ProxyContract,
|
ERC20ProxyContract,
|
||||||
ERC721ProxyContract,
|
ERC721ProxyContract,
|
||||||
MultiAssetProxyContract,
|
MultiAssetProxyContract,
|
||||||
|
StaticCallProxyContract,
|
||||||
|
TestStaticCallTargetContract,
|
||||||
} from '@0x/contracts-asset-proxy';
|
} from '@0x/contracts-asset-proxy';
|
||||||
import {
|
import {
|
||||||
artifacts as erc1155Artifacts,
|
artifacts as erc1155Artifacts,
|
||||||
@ -21,6 +23,7 @@ import { BlockchainLifecycle } from '@0x/dev-utils';
|
|||||||
import { assetDataUtils } from '@0x/order-utils';
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { AssetProxyId } from '@0x/types';
|
import { AssetProxyId } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import { artifacts, LibAssetDataContract } from '../src';
|
import { artifacts, LibAssetDataContract } from '../src';
|
||||||
|
|
||||||
@ -65,6 +68,8 @@ describe('LibAssetData', () => {
|
|||||||
let erc721Proxy: ERC721ProxyContract;
|
let erc721Proxy: ERC721ProxyContract;
|
||||||
let erc1155Proxy: ERC1155ProxyContract;
|
let erc1155Proxy: ERC1155ProxyContract;
|
||||||
let multiAssetProxy: MultiAssetProxyContract;
|
let multiAssetProxy: MultiAssetProxyContract;
|
||||||
|
let staticCallProxy: StaticCallProxyContract;
|
||||||
|
let staticCallTarget: TestStaticCallTargetContract;
|
||||||
let libAssetData: LibAssetDataContract;
|
let libAssetData: LibAssetDataContract;
|
||||||
|
|
||||||
let tokenOwnerAddress: string;
|
let tokenOwnerAddress: string;
|
||||||
@ -110,11 +115,17 @@ describe('LibAssetData', () => {
|
|||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
);
|
);
|
||||||
|
staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.StaticCallProxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
|
||||||
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc20Proxy.address);
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc20Proxy.address);
|
||||||
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc721Proxy.address);
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc721Proxy.address);
|
||||||
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc1155Proxy.address);
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc1155Proxy.address);
|
||||||
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(multiAssetProxy.address);
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(multiAssetProxy.address);
|
||||||
|
await exchange.registerAssetProxy.awaitTransactionSuccessAsync(staticCallProxy.address);
|
||||||
|
|
||||||
libAssetData = await LibAssetDataContract.deployFrom0xArtifactAsync(
|
libAssetData = await LibAssetDataContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.LibAssetData,
|
artifacts.LibAssetData,
|
||||||
@ -123,6 +134,12 @@ describe('LibAssetData', () => {
|
|||||||
exchange.address,
|
exchange.address,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
||||||
|
proxyArtifacts.TestStaticCallTarget,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
|
||||||
[tokenOwnerAddress] = await web3Wrapper.getAvailableAddressesAsync();
|
[tokenOwnerAddress] = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
|
||||||
erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||||
@ -324,6 +341,32 @@ describe('LibAssetData', () => {
|
|||||||
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, fakeAssetData);
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, fakeAssetData);
|
||||||
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return a balance of MAX_UINT256 if the the StaticCallProxy assetData contains data for a successful staticcall', async () => {
|
||||||
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||||
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a balance of 0 if the the StaticCallProxy assetData contains data for an unsuccessful staticcall', async () => {
|
||||||
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
|
||||||
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
|
const balance = await libAssetData.getBalance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getAssetProxyAllowance', () => {
|
describe('getAssetProxyAllowance', () => {
|
||||||
@ -399,6 +442,17 @@ describe('LibAssetData', () => {
|
|||||||
const allowance = await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, fakeAssetData);
|
const allowance = await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, fakeAssetData);
|
||||||
expect(allowance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(allowance).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return an allowance of MAX_UINT256 for any staticCallAssetData', async () => {
|
||||||
|
const staticCallData = AssetProxyId.StaticCall;
|
||||||
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
|
staticCallTarget.address,
|
||||||
|
staticCallData,
|
||||||
|
constants.KECCAK256_NULL,
|
||||||
|
);
|
||||||
|
const allowance = await libAssetData.getAssetProxyAllowance.callAsync(tokenOwnerAddress, assetData);
|
||||||
|
expect(allowance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getBatchBalances', () => {
|
describe('getBatchBalances', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user