aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contract-wrappers
diff options
context:
space:
mode:
Diffstat (limited to 'packages/contract-wrappers')
-rw-r--r--packages/contract-wrappers/CHANGELOG.json9
-rw-r--r--packages/contract-wrappers/src/contract_wrappers.ts12
-rw-r--r--packages/contract-wrappers/src/index.ts7
-rw-r--r--packages/contract-wrappers/src/utils/transaction_encoder.ts17
-rw-r--r--packages/contract-wrappers/test/calldata_decoder_test.ts127
5 files changed, 171 insertions, 1 deletions
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index 73c8e6070..6e0d1ca4b 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "7.1.0",
+ "changes": [
+ {
+ "note": "Added calldata decoding to ContractWrappers",
+ "pr": 1569
+ }
+ ]
+ },
+ {
"version": "7.0.2",
"changes": [
{
diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts
index 4e594593e..f43dc5d26 100644
--- a/packages/contract-wrappers/src/contract_wrappers.ts
+++ b/packages/contract-wrappers/src/contract_wrappers.ts
@@ -1,4 +1,5 @@
import {
+ DutchAuction,
ERC20Proxy,
ERC20Token,
ERC721Proxy,
@@ -8,6 +9,7 @@ import {
OrderValidator,
WETH9,
} from '@0x/contract-artifacts';
+import { AbiDecoder } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
@@ -87,6 +89,7 @@ export class ContractWrappers {
};
this._web3Wrapper = new Web3Wrapper(provider, txDefaults);
const artifactsArray = [
+ DutchAuction,
ERC20Proxy,
ERC20Token,
ERC721Proxy,
@@ -97,7 +100,7 @@ export class ContractWrappers {
WETH9,
];
_.forEach(artifactsArray, artifact => {
- this._web3Wrapper.abiDecoder.addABI(artifact.compilerOutput.abi);
+ this._web3Wrapper.abiDecoder.addABI(artifact.compilerOutput.abi, artifact.contractName);
});
const blockPollingIntervalMs = _.isUndefined(config.blockPollingIntervalMs)
? constants.DEFAULT_BLOCK_POLLING_INTERVAL
@@ -168,4 +171,11 @@ export class ContractWrappers {
public getProvider(): Provider {
return this._web3Wrapper.getProvider();
}
+ /**
+ * Get the abi decoder instance currently used by contract-wrappers
+ * @return AbiDecoder instance
+ */
+ public getAbiDecoder(): AbiDecoder {
+ return this._web3Wrapper.abiDecoder;
+ }
}
diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts
index 69bbe3c91..5fc400edf 100644
--- a/packages/contract-wrappers/src/index.ts
+++ b/packages/contract-wrappers/src/index.ts
@@ -38,6 +38,8 @@ export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper';
export { TransactionEncoder } from './utils/transaction_encoder';
+export { AbiDecoder, DecodedCalldata } from '@0x/utils';
+
export {
ContractWrappersError,
ForwarderWrapperError,
@@ -83,6 +85,11 @@ export {
JSONRPCResponseError,
AbiDefinition,
LogWithDecodedArgs,
+ LogEntry,
+ DecodedLogEntry,
+ DecodedLogEntryEvent,
+ LogEntryEvent,
+ RawLog,
FunctionAbi,
EventAbi,
EventParameter,
diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts
index 307487a9b..0832ee73a 100644
--- a/packages/contract-wrappers/src/utils/transaction_encoder.ts
+++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts
@@ -242,6 +242,23 @@ export class TransactionEncoder {
return abiEncodedData;
}
/**
+ * Encodes a matchOrders transaction.
+ * @param leftOrder First order to match.
+ * @param rightOrder Second order to match.
+ * @return Hex encoded abi of the function call.
+ */
+ public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string {
+ assert.doesConformToSchema('leftOrder', leftOrder, schemas.orderSchema);
+ assert.doesConformToSchema('rightOrder', rightOrder, schemas.orderSchema);
+ const abiEncodedData = this._getExchangeContract().matchOrders.getABIEncodedTransactionData(
+ leftOrder,
+ rightOrder,
+ leftOrder.signature,
+ rightOrder.signature,
+ );
+ return abiEncodedData;
+ }
+ /**
* Encodes a preSign transaction.
* @param hash Hash to pre-sign
* @param signerAddress Address that should have signed the given hash.
diff --git a/packages/contract-wrappers/test/calldata_decoder_test.ts b/packages/contract-wrappers/test/calldata_decoder_test.ts
new file mode 100644
index 000000000..ba1539ef5
--- /dev/null
+++ b/packages/contract-wrappers/test/calldata_decoder_test.ts
@@ -0,0 +1,127 @@
+import { constants, OrderFactory } from '@0x/contracts-test-utils';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { assetDataUtils } from '@0x/order-utils';
+import { SignedOrder } from '@0x/types';
+import { addressUtils, BigNumber } from '@0x/utils';
+import * as chai from 'chai';
+import * as _ from 'lodash';
+import 'mocha';
+
+import { ContractAddresses, ContractWrappers } from '../src';
+
+import { chaiSetup } from './utils/chai_setup';
+import { migrateOnceAsync } from './utils/migrate';
+import { provider, web3Wrapper } from './utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+
+describe('ABI Decoding Calldata', () => {
+ const defaultERC20MakerAssetAddress = addressUtils.generatePseudoRandomAddress();
+ const matchOrdersSignature =
+ 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)';
+ let signedOrderLeft: SignedOrder;
+ let signedOrderRight: SignedOrder;
+ let orderLeft = {};
+ let orderRight = {};
+ let matchOrdersTxData: string;
+ let contractAddresses: ContractAddresses;
+ let contractWrappers: ContractWrappers;
+
+ before(async () => {
+ // Create accounts
+ const accounts = await web3Wrapper.getAvailableAddressesAsync();
+ const [makerAddressLeft, makerAddressRight] = accounts;
+ const [privateKeyLeft, privateKeyRight] = constants.TESTRPC_PRIVATE_KEYS;
+ const exchangeAddress = addressUtils.generatePseudoRandomAddress();
+ const feeRecipientAddress = addressUtils.generatePseudoRandomAddress();
+ // Create orders to match.
+ // Values are arbitrary, with the exception of maker addresses (generated above).
+ orderLeft = {
+ makerAddress: makerAddressLeft,
+ makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
+ makerAssetAmount: new BigNumber(10),
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
+ takerAssetAmount: new BigNumber(1),
+ feeRecipientAddress,
+ makerFee: new BigNumber(0),
+ takerFee: new BigNumber(0),
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ expirationTimeSeconds: new BigNumber(1549498915),
+ salt: new BigNumber(217),
+ };
+ orderRight = {
+ makerAddress: makerAddressRight,
+ makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
+ makerAssetAmount: new BigNumber(1),
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
+ takerAssetAmount: new BigNumber(8),
+ feeRecipientAddress,
+ makerFee: new BigNumber(0),
+ takerFee: new BigNumber(0),
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ expirationTimeSeconds: new BigNumber(1549498915),
+ salt: new BigNumber(50010),
+ };
+ const orderFactoryLeft = new OrderFactory(privateKeyLeft, orderLeft);
+ signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ exchangeAddress });
+ const orderFactoryRight = new OrderFactory(privateKeyRight, orderRight);
+ signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ exchangeAddress });
+ // Encode match orders transaction
+ contractAddresses = await migrateOnceAsync();
+ await blockchainLifecycle.startAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
+ contractWrappers = new ContractWrappers(provider, config);
+ const transactionEncoder = await contractWrappers.exchange.transactionEncoderAsync();
+ matchOrdersTxData = transactionEncoder.matchOrdersTx(signedOrderLeft, signedOrderRight);
+ });
+
+ describe('decode', () => {
+ it('should successfully decode DutchAuction.matchOrders calldata', async () => {
+ const contractName = 'DutchAuction';
+ const decodedTxData = contractWrappers
+ .getAbiDecoder()
+ .decodeCalldataOrThrow(matchOrdersTxData, contractName);
+ const expectedFunctionName = 'matchOrders';
+ const expectedFunctionArguments = {
+ buyOrder: orderLeft,
+ sellOrder: orderRight,
+ buySignature: signedOrderLeft.signature,
+ sellSignature: signedOrderRight.signature,
+ };
+ expect(decodedTxData.functionName).to.be.equal(expectedFunctionName);
+ expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature);
+ expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments);
+ });
+ it('should successfully decode Exchange.matchOrders calldata (and distinguish from DutchAuction.matchOrders)', async () => {
+ const contractName = 'Exchange';
+ const decodedTxData = contractWrappers
+ .getAbiDecoder()
+ .decodeCalldataOrThrow(matchOrdersTxData, contractName);
+ const expectedFunctionName = 'matchOrders';
+ const expectedFunctionArguments = {
+ leftOrder: orderLeft,
+ rightOrder: orderRight,
+ leftSignature: signedOrderLeft.signature,
+ rightSignature: signedOrderRight.signature,
+ };
+ expect(decodedTxData.functionName).to.be.equal(expectedFunctionName);
+ expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature);
+ expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments);
+ });
+ it('should throw if cannot decode calldata', async () => {
+ const badTxData = '0x01020304';
+ expect(() => {
+ contractWrappers.getAbiDecoder().decodeCalldataOrThrow(badTxData);
+ }).to.throw("No functions registered for selector '0x01020304'");
+ });
+ });
+});