diff --git a/contracts/coordinator/test/coordinator.ts b/contracts/coordinator/test/coordinator.ts index 912d48d922..1fe84e3184 100644 --- a/contracts/coordinator/test/coordinator.ts +++ b/contracts/coordinator/test/coordinator.ts @@ -21,7 +21,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; @@ -33,6 +33,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi); // tslint:disable:no-unnecessary-type-assertion describe('Coordinator tests', () => { + let chainId: number; let makerAddress: string; let owner: string; let takerAddress: string; @@ -58,6 +59,7 @@ describe('Coordinator tests', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); const accounts = await web3Wrapper.getAvailableAddressesAsync(); const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts.slice(0, 4)); @@ -75,6 +77,7 @@ describe('Coordinator tests', () => { provider, txDefaults, assetDataUtils.encodeERC20AssetData(zrxToken.address), + new BigNumber(chainId), ); await web3Wrapper.awaitTransactionSuccessAsync( @@ -92,12 +95,14 @@ describe('Coordinator tests', () => { provider, txDefaults, exchange.address, + new BigNumber(chainId), ); // Configure order defaults const defaultOrderParams = { ...devConstants.STATIC_ORDER_PARAMS, exchangeAddress: exchange.address, + chainId, senderAddress: coordinatorContract.address, makerAddress, feeRecipientAddress, @@ -108,9 +113,21 @@ describe('Coordinator tests', () => { const takerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; const feeRecipientPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)]; orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams); - makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address); - takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address); - approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, coordinatorContract.address); + makerTransactionFactory = new TransactionFactory( + makerPrivateKey, + exchange.address, + chainId, + ); + takerTransactionFactory = new TransactionFactory( + takerPrivateKey, + exchange.address, + chainId, + ); + approvalFactory = new ApprovalFactory( + feeRecipientPrivateKey, + coordinatorContract.address, + chainId, + ); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); diff --git a/contracts/coordinator/test/libs.ts b/contracts/coordinator/test/libs.ts index 8c08f0ec59..1ef208b637 100644 --- a/contracts/coordinator/test/libs.ts +++ b/contracts/coordinator/test/libs.ts @@ -1,7 +1,7 @@ import { addressUtils, chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { transactionHashUtils } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import { artifacts, CoordinatorContract, hashUtils } from '../src'; @@ -12,6 +12,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('Libs tests', () => { let coordinatorContract: CoordinatorContract; + let chainId: number; const exchangeAddress = addressUtils.generatePseudoRandomAddress(); before(async () => { @@ -21,11 +22,13 @@ describe('Libs tests', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( artifacts.Coordinator, provider, txDefaults, exchangeAddress, + new BigNumber(chainId), ); }); beforeEach(async () => { @@ -39,6 +42,7 @@ describe('Libs tests', () => { it('should return the correct transaction hash', async () => { const tx = { verifyingContractAddress: exchangeAddress, + chainId, salt: new BigNumber(0), signerAddress: constants.NULL_ADDRESS, data: '0x1234', @@ -53,6 +57,7 @@ describe('Libs tests', () => { it('should return the correct approval hash', async () => { const signedTx = { verifyingContractAddress: exchangeAddress, + chainId, salt: new BigNumber(0), signerAddress: constants.NULL_ADDRESS, data: '0x1234', @@ -69,6 +74,7 @@ describe('Libs tests', () => { const expectedApprovalHash = hashUtils.getApprovalHashHex( signedTx, coordinatorContract.address, + chainId, txOrigin, approvalExpirationTimeSeconds, ); diff --git a/contracts/coordinator/test/mixins.ts b/contracts/coordinator/test/mixins.ts index a500333048..45f7961f1d 100644 --- a/contracts/coordinator/test/mixins.ts +++ b/contracts/coordinator/test/mixins.ts @@ -12,7 +12,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { transactionHashUtils } from '@0x/order-utils'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import * as ethUtil from 'ethereumjs-util'; @@ -23,6 +23,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('Mixins tests', () => { + let chainId: number; let transactionSignerAddress: string; let approvalSignerAddress1: string; let approvalSignerAddress2: string; @@ -40,16 +41,19 @@ describe('Mixins tests', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); mixins = await CoordinatorContract.deployFrom0xArtifactAsync( artifacts.Coordinator, provider, txDefaults, exchangeAddress, + new BigNumber(chainId), ); const accounts = await web3Wrapper.getAvailableAddressesAsync(); [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3); defaultOrder = { exchangeAddress: devConstants.NULL_ADDRESS, + chainId, makerAddress: devConstants.NULL_ADDRESS, takerAddress: devConstants.NULL_ADDRESS, senderAddress: mixins.address, @@ -68,9 +72,21 @@ describe('Mixins tests', () => { devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)]; const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)]; const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)]; - transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress); - approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); - approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); + transactionFactory = new TransactionFactory( + transactionSignerPrivateKey, + exchangeAddress, + chainId, + ); + approvalFactory1 = new ApprovalFactory( + approvalSignerPrivateKey1, + mixins.address, + chainId, + ); + approvalFactory2 = new ApprovalFactory( + approvalSignerPrivateKey2, + mixins.address, + chainId, + ); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); diff --git a/contracts/coordinator/test/utils/approval_factory.ts b/contracts/coordinator/test/utils/approval_factory.ts index f0c5ea145d..9e35b81a37 100644 --- a/contracts/coordinator/test/utils/approval_factory.ts +++ b/contracts/coordinator/test/utils/approval_factory.ts @@ -8,10 +8,16 @@ import { hashUtils, SignedCoordinatorApproval } from './index'; export class ApprovalFactory { private readonly _privateKey: Buffer; private readonly _verifyingContractAddress: string; + private readonly _chainId: number; - constructor(privateKey: Buffer, verifyingContractAddress: string) { + constructor( + privateKey: Buffer, + verifyingContractAddress: string, + chainId: number, + ) { this._privateKey = privateKey; this._verifyingContractAddress = verifyingContractAddress; + this._chainId = chainId; } public newSignedApproval( @@ -23,6 +29,7 @@ export class ApprovalFactory { const approvalHashBuff = hashUtils.getApprovalHashBuffer( transaction, this._verifyingContractAddress, + this._chainId, txOrigin, approvalExpirationTimeSeconds, ); diff --git a/contracts/coordinator/test/utils/hash_utils.ts b/contracts/coordinator/test/utils/hash_utils.ts index 6e2ca8141c..e16736e70e 100644 --- a/contracts/coordinator/test/utils/hash_utils.ts +++ b/contracts/coordinator/test/utils/hash_utils.ts @@ -6,7 +6,6 @@ import * as _ from 'lodash'; export const hashUtils = { getApprovalHashBuffer( transaction: SignedZeroExTransaction, - chainId: BigNumber, verifyingContractAddress: string, txOrigin: string, approvalExpirationTimeSeconds: BigNumber, @@ -22,7 +21,6 @@ export const hashUtils = { }, getApprovalHashHex( transaction: SignedZeroExTransaction, - chainId: BigNumber, verifyingContractAddress: string, txOrigin: string, approvalExpirationTimeSeconds: BigNumber, @@ -30,7 +28,6 @@ export const hashUtils = { const hashHex = `0x${hashUtils .getApprovalHashBuffer( transaction, - chainId, verifyingContractAddress, txOrigin, approvalExpirationTimeSeconds) diff --git a/contracts/exchange-libs/package.json b/contracts/exchange-libs/package.json index 5954916aa5..e7b41863f8 100644 --- a/contracts/exchange-libs/package.json +++ b/contracts/exchange-libs/package.json @@ -34,7 +34,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "./generated-artifacts/@(LibAbiEncoder|LibAssetProxyErrors|LibConstants|LibEIP712|LibFillResults|LibMath|LibOrder|TestLibs).json", + "abis": "./generated-artifacts/@(LibAbiEncoder|LibAssetProxyErrors|LibConstants|LibEIP712|LibEIP712ExchangeDomainConstants|LibEIP712ExchangeDomain|LibFillResults|LibMath|LibOrder|TestLibs).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/exchange-libs/test/exchange_libs.ts b/contracts/exchange-libs/test/exchange_libs.ts index b613231895..d713dfe268 100644 --- a/contracts/exchange-libs/test/exchange_libs.ts +++ b/contracts/exchange-libs/test/exchange_libs.ts @@ -10,7 +10,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import { TestLibsContract } from '../generated-wrappers/test_libs'; @@ -22,6 +22,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('Exchange libs', () => { + let chainId: number; let signedOrder: SignedOrder; let orderFactory: OrderFactory; let libs: TestLibsContract; @@ -35,11 +36,18 @@ describe('Exchange libs', () => { before(async () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); const makerAddress = accounts[0]; - libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); + chainId = await providerUtils.getChainIdAsync(provider); + libs = await TestLibsContract.deployFrom0xArtifactAsync( + artifacts.TestLibs, + provider, + txDefaults, + new BigNumber(chainId), + ); const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, exchangeAddress: libs.address, + chainId, makerAddress, feeRecipientAddress: addressUtils.generatePseudoRandomAddress(), makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), diff --git a/contracts/exchange/test/core.ts b/contracts/exchange/test/core.ts index 82e27dcf5f..809f752297 100644 --- a/contracts/exchange/test/core.ts +++ b/contracts/exchange/test/core.ts @@ -33,7 +33,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; @@ -55,6 +55,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); // tslint:disable:no-unnecessary-type-assertion describe('Exchange core', () => { + let chainId: number; let makerAddress: string; let owner: string; let takerAddress: string; @@ -102,6 +103,7 @@ describe('Exchange core', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); const accounts = await web3Wrapper.getAvailableAddressesAsync(); const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4)); @@ -136,6 +138,7 @@ describe('Exchange core', () => { provider, txDefaults, assetDataUtils.encodeERC20AssetData(zrxToken.address), + new BigNumber(chainId), ); maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync( artifacts.TestStaticCallReceiver, @@ -206,6 +209,7 @@ describe('Exchange core', () => { const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, exchangeAddress: exchange.address, + chainId, makerAddress, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), diff --git a/contracts/exchange/test/internal.ts b/contracts/exchange/test/internal.ts index 7a1e12a7a1..f23fc0cbc2 100644 --- a/contracts/exchange/test/internal.ts +++ b/contracts/exchange/test/internal.ts @@ -12,7 +12,7 @@ import { } from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { Order, RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -37,6 +37,7 @@ const emptyOrder: Order = { takerAssetData: '0x', salt: new BigNumber(0), exchangeAddress: constants.NULL_ADDRESS, + chainId: 0, // To be filled in later. feeRecipientAddress: constants.NULL_ADDRESS, expirationTimeSeconds: new BigNumber(0), }; @@ -49,6 +50,7 @@ const emptySignedOrder: SignedOrder = { const overflowErrorForCall = new Error(RevertReason.Uint256Overflow); describe('Exchange core internal functions', () => { + let chainId: number; let testExchange: TestExchangeInternalsContract; let overflowErrorForSendTransaction: Error | undefined; let divisionByZeroErrorForCall: Error | undefined; @@ -61,10 +63,15 @@ describe('Exchange core internal functions', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); + emptyOrder.chainId = chainId; + emptySignedOrder.chainId = chainId; + testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync( artifacts.TestExchangeInternals, provider, txDefaults, + new BigNumber(chainId), ); overflowErrorForSendTransaction = new Error( await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow), diff --git a/contracts/exchange/test/match_orders.ts b/contracts/exchange/test/match_orders.ts index 783adfe487..d6a25df97a 100644 --- a/contracts/exchange/test/match_orders.ts +++ b/contracts/exchange/test/match_orders.ts @@ -15,7 +15,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -34,6 +34,7 @@ chaiSetup.configure(); const expect = chai.expect; describe('matchOrders', () => { + let chainId: number; let makerAddressLeft: string; let makerAddressRight: string; let owner: string; @@ -76,6 +77,8 @@ describe('matchOrders', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + // Get the chain ID. + chainId = await providerUtils.getChainIdAsync(provider); // Create accounts const accounts = await web3Wrapper.getAvailableAddressesAsync(); // Hack(albrow): Both Prettier and TSLint insert a trailing comma below @@ -119,6 +122,7 @@ describe('matchOrders', () => { provider, txDefaults, assetDataUtils.encodeERC20AssetData(zrxToken.address), + new BigNumber(chainId) ); exchangeWrapper = new ExchangeWrapper(exchange, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); @@ -153,6 +157,7 @@ describe('matchOrders', () => { ...constants.STATIC_ORDER_PARAMS, makerAddress: makerAddressLeft, exchangeAddress: exchange.address, + chainId, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), feeRecipientAddress: feeRecipientAddressLeft, @@ -161,6 +166,7 @@ describe('matchOrders', () => { ...constants.STATIC_ORDER_PARAMS, makerAddress: makerAddressRight, exchangeAddress: exchange.address, + chainId, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), feeRecipientAddress: feeRecipientAddressRight, @@ -175,6 +181,7 @@ describe('matchOrders', () => { artifacts.TestExchangeInternals, provider, txDefaults, + new BigNumber(chainId), ); }); beforeEach(async () => { diff --git a/contracts/exchange/test/signature_validator.ts b/contracts/exchange/test/signature_validator.ts index 33510e50c0..b84edf9686 100644 --- a/contracts/exchange/test/signature_validator.ts +++ b/contracts/exchange/test/signature_validator.ts @@ -12,6 +12,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import ethUtil = require('ethereumjs-util'); @@ -31,6 +32,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); // tslint:disable:no-unnecessary-type-assertion describe('MixinSignatureValidator', () => { + let chainId: number; let signedOrder: SignedOrder; let orderFactory: OrderFactory; let signatureValidator: TestSignatureValidatorContract; @@ -51,6 +53,7 @@ describe('MixinSignatureValidator', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); const accounts = await web3Wrapper.getAvailableAddressesAsync(); const makerAddress = accounts[0]; signerAddress = makerAddress; @@ -59,6 +62,7 @@ describe('MixinSignatureValidator', () => { artifacts.TestSignatureValidator, provider, txDefaults, + new BigNumber(chainId), ); testWallet = await WalletContract.deployFrom0xArtifactAsync( artifacts.Wallet, @@ -98,6 +102,7 @@ describe('MixinSignatureValidator', () => { const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, exchangeAddress: signatureValidator.address, + chainId, makerAddress, feeRecipientAddress: addressUtils.generatePseudoRandomAddress(), makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), diff --git a/contracts/exchange/test/transactions.ts b/contracts/exchange/test/transactions.ts index 4f8c075794..784e640a7f 100644 --- a/contracts/exchange/test/transactions.ts +++ b/contracts/exchange/test/transactions.ts @@ -15,7 +15,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { OrderWithoutExchangeAddress, RevertReason, SignedOrder, SignedZeroExTransaction } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -26,6 +26,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('Exchange transactions', () => { + let chainId: number; let senderAddress: string; let owner: string; let makerAddress: string; @@ -66,6 +67,7 @@ describe('Exchange transactions', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); const accounts = await web3Wrapper.getAvailableAddressesAsync(); const usedAddresses = ([owner, senderAddress, makerAddress, takerAddress, feeRecipientAddress] = _.slice( accounts, @@ -88,6 +90,7 @@ describe('Exchange transactions', () => { provider, txDefaults, assetDataUtils.encodeERC20AssetData(zrxToken.address), + new BigNumber(chainId) ); exchangeWrapper = new ExchangeWrapper(exchange, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); @@ -104,6 +107,7 @@ describe('Exchange transactions', () => { ...constants.STATIC_ORDER_PARAMS, senderAddress, exchangeAddress: exchange.address, + chainId, makerAddress, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress), @@ -112,8 +116,16 @@ describe('Exchange transactions', () => { makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams); - makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address); - takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address); + makerTransactionFactory = new TransactionFactory( + makerPrivateKey, + exchange.address, + chainId, + ); + takerTransactionFactory = new TransactionFactory( + takerPrivateKey, + exchange.address, + chainId, + ); }); describe('executeTransaction', () => { describe('fillOrder', () => { @@ -346,6 +358,7 @@ describe('Exchange transactions', () => { ...constants.STATIC_ORDER_PARAMS, senderAddress: whitelist.address, exchangeAddress: exchange.address, + chainId, makerAddress, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress), diff --git a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts index a15b27e12b..d5e1c912e3 100644 --- a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts +++ b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts @@ -63,6 +63,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( const supportedProvider = web3Wrapper.getProvider(); const provider = providerUtils.standardizeOrThrow(supportedProvider); + const chainId = await providerUtils.getChainIdAsync(provider); const erc20Wrapper = new ERC20Wrapper(provider, userAddresses, ownerAddress); const erc721Wrapper = new ERC721Wrapper(provider, userAddresses, ownerAddress); @@ -102,6 +103,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( provider, txDefaults, zrxAssetData, + new BigNumber(chainId) ); const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress); @@ -129,12 +131,14 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( erc721Token, erc721Balances, exchangeContract.address, + chainId ); const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync( libsArtifacts.TestLibs, provider, txDefaults, + new BigNumber(chainId), ); const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils( @@ -404,7 +408,6 @@ export class FillOrderCombinatorialUtils { try { await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( exchangeTransferSimulator, - provider, signedOrder, takerAssetFillAmount, this.takerAddress, @@ -627,7 +630,11 @@ export class FillOrderCombinatorialUtils { balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher, ): Promise { - const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); + const orderStateUtils = new OrderStateUtils( + balanceAndProxyAllowanceFetcher, + orderFilledCancelledFetcher, + signedOrder.chainId, + ); const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync( signedOrder, this.takerAddress, diff --git a/contracts/exchange/test/utils/order_factory_from_scenario.ts b/contracts/exchange/test/utils/order_factory_from_scenario.ts index 6f56459060..4417f71a7f 100644 --- a/contracts/exchange/test/utils/order_factory_from_scenario.ts +++ b/contracts/exchange/test/utils/order_factory_from_scenario.ts @@ -32,6 +32,7 @@ export class OrderFactoryFromScenario { private readonly _erc721Token: DummyERC721TokenContract; private readonly _erc721Balances: ERC721TokenIdsByOwner; private readonly _exchangeAddress: string; + private readonly _chainId: number; constructor( userAddresses: string[], zrxAddress: string, @@ -41,6 +42,7 @@ export class OrderFactoryFromScenario { erc721Token: DummyERC721TokenContract, erc721Balances: ERC721TokenIdsByOwner, exchangeAddress: string, + chainId: number ) { this._userAddresses = userAddresses; this._zrxAddress = zrxAddress; @@ -50,6 +52,7 @@ export class OrderFactoryFromScenario { this._erc721Token = erc721Token; this._erc721Balances = erc721Balances; this._exchangeAddress = exchangeAddress; + this._chainId = chainId; } public generateOrder(orderScenario: OrderScenario): Order { const makerAddress = this._userAddresses[1]; @@ -285,6 +288,7 @@ export class OrderFactoryFromScenario { takerAssetData, salt: generatePseudoRandomSalt(), exchangeAddress: this._exchangeAddress, + chainId: this._chainId, feeRecipientAddress, expirationTimeSeconds, }; diff --git a/contracts/exchange/test/wrapper.ts b/contracts/exchange/test/wrapper.ts index 8a86f51307..ecfa568db5 100644 --- a/contracts/exchange/test/wrapper.ts +++ b/contracts/exchange/test/wrapper.ts @@ -17,7 +17,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -29,6 +29,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('Exchange wrappers', () => { + let chainId: number; let makerAddress: string; let owner: string; let takerAddress: string; @@ -62,6 +63,7 @@ describe('Exchange wrappers', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); const accounts = await web3Wrapper.getAvailableAddressesAsync(); const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4)); @@ -88,6 +90,7 @@ describe('Exchange wrappers', () => { provider, txDefaults, assetDataUtils.encodeERC20AssetData(zrxToken.address), + new BigNumber(chainId) ); exchangeWrapper = new ExchangeWrapper(exchange, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); @@ -119,6 +122,7 @@ describe('Exchange wrappers', () => { const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, exchangeAddress: exchange.address, + chainId, makerAddress, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), diff --git a/contracts/extensions/test/balance_threshold_filter.ts b/contracts/extensions/test/balance_threshold_filter.ts index 530eefd51b..be669c871b 100644 --- a/contracts/extensions/test/balance_threshold_filter.ts +++ b/contracts/extensions/test/balance_threshold_filter.ts @@ -2,7 +2,7 @@ import { ExchangeContract, ExchangeWrapper } from '@0x/contracts-exchange'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { Order, RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; @@ -40,6 +40,7 @@ describe(ContractName.BalanceThresholdFilter, () => { const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT); const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT); + let chainId: number; let validMakerAddress: string; let validMakerAddress2: string; let owner: string; @@ -88,6 +89,8 @@ describe(ContractName.BalanceThresholdFilter, () => { }; before(async () => { + // Get the chain ID. + chainId = await providerUtils.getChainIdAsync(provider); // Create accounts await blockchainLifecycle.startAsync(); const accounts = await web3Wrapper.getAvailableAddressesAsync(); @@ -131,6 +134,7 @@ describe(ContractName.BalanceThresholdFilter, () => { provider, txDefaults, zrxAssetData, + new BigNumber(chainId), ); exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); // Register proxies @@ -164,6 +168,7 @@ describe(ContractName.BalanceThresholdFilter, () => { // Default order parameters defaultOrderParams = { exchangeAddress: exchangeInstance.address, + chainId, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), @@ -197,25 +202,25 @@ describe(ContractName.BalanceThresholdFilter, () => { erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper( erc20BalanceThresholdFilterInstance, exchangeInstance, - new TransactionFactory(takerPrivateKey, exchangeInstance.address), + new TransactionFactory(takerPrivateKey, exchangeInstance.address, chainId), provider, ); erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper( erc721BalanceThresholdFilterInstance, exchangeInstance, - new TransactionFactory(takerPrivateKey, exchangeInstance.address), + new TransactionFactory(takerPrivateKey, exchangeInstance.address, chainId), provider, ); erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper( erc721BalanceThresholdFilterInstance, exchangeInstance, - new TransactionFactory(makerPrivateKey, exchangeInstance.address), + new TransactionFactory(makerPrivateKey, exchangeInstance.address, chainId), provider, ); erc721NonValidBalanceThresholdWrapper = new BalanceThresholdWrapper( erc721BalanceThresholdFilterInstance, exchangeInstance, - new TransactionFactory(invalidAddressPrivateKey, exchangeInstance.address), + new TransactionFactory(invalidAddressPrivateKey, exchangeInstance.address, chainId), provider, ); }); diff --git a/contracts/extensions/test/dutch_auction.ts b/contracts/extensions/test/dutch_auction.ts index 639f61999d..47788cb303 100644 --- a/contracts/extensions/test/dutch_auction.ts +++ b/contracts/extensions/test/dutch_auction.ts @@ -18,7 +18,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -31,6 +31,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const DECIMALS_DEFAULT = 18; describe(ContractName.DutchAuction, () => { + let chainId: number; let makerAddress: string; let owner: string; let takerAddress: string; @@ -62,6 +63,8 @@ describe(ContractName.DutchAuction, () => { before(async () => { await blockchainLifecycle.startAsync(); + + chainId = await providerUtils.getChainIdAsync(provider); const accounts = await web3Wrapper.getAvailableAddressesAsync(); const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); @@ -91,6 +94,7 @@ describe(ContractName.DutchAuction, () => { provider, txDefaults, zrxAssetData, + new BigNumber(chainId), ); const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); @@ -145,6 +149,7 @@ describe(ContractName.DutchAuction, () => { const sellerDefaultOrderParams = { salt: generatePseudoRandomSalt(), exchangeAddress: exchangeInstance.address, + chainId, makerAddress, feeRecipientAddress, // taker address or sender address should be set to the ducth auction contract diff --git a/contracts/extensions/test/order_matcher.ts b/contracts/extensions/test/order_matcher.ts index 99ec0d06d9..04ad9b3e2d 100644 --- a/contracts/extensions/test/order_matcher.ts +++ b/contracts/extensions/test/order_matcher.ts @@ -23,7 +23,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; @@ -36,6 +36,7 @@ chaiSetup.configure(); const expect = chai.expect; // tslint:disable:no-unnecessary-type-assertion describe('OrderMatcher', () => { + let chainId: number; let makerAddressLeft: string; let makerAddressRight: string; let owner: string; @@ -69,6 +70,7 @@ describe('OrderMatcher', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { + chainId = await providerUtils.getChainIdAsync(provider); // Create accounts const accounts = await web3Wrapper.getAvailableAddressesAsync(); // Hack(albrow): Both Prettier and TSLint insert a trailing comma below @@ -110,6 +112,7 @@ describe('OrderMatcher', () => { provider, txDefaults, assetDataUtils.encodeERC20AssetData(zrxToken.address), + new BigNumber(chainId), ); exchangeWrapper = new ExchangeWrapper(exchange, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); @@ -165,6 +168,7 @@ describe('OrderMatcher', () => { ...constants.STATIC_ORDER_PARAMS, makerAddress: makerAddressLeft, exchangeAddress: exchange.address, + chainId, makerAssetData: leftMakerAssetData, takerAssetData: leftTakerAssetData, feeRecipientAddress: feeRecipientAddressLeft, @@ -175,6 +179,7 @@ describe('OrderMatcher', () => { ...constants.STATIC_ORDER_PARAMS, makerAddress: makerAddressRight, exchangeAddress: exchange.address, + chainId, makerAssetData: leftTakerAssetData, takerAssetData: leftMakerAssetData, feeRecipientAddress: feeRecipientAddressRight, @@ -199,6 +204,7 @@ describe('OrderMatcher', () => { provider, txDefaults, constants.NULL_BYTES, + new BigNumber(chainId), ); return expectContractCreationFailedAsync( (OrderMatcherContract.deployFrom0xArtifactAsync( diff --git a/contracts/test-utils/src/transaction_factory.ts b/contracts/test-utils/src/transaction_factory.ts index e6cd4c23f6..0dc52e4634 100644 --- a/contracts/test-utils/src/transaction_factory.ts +++ b/contracts/test-utils/src/transaction_factory.ts @@ -8,9 +8,12 @@ export class TransactionFactory { private readonly _signerBuff: Buffer; private readonly _exchangeAddress: string; private readonly _privateKey: Buffer; - constructor(privateKey: Buffer, exchangeAddress: string) { + private readonly _chainId: number; + + constructor(privateKey: Buffer, exchangeAddress: string, chainId: number) { this._privateKey = privateKey; this._exchangeAddress = exchangeAddress; + this._chainId = chainId; this._signerBuff = ethUtil.privateToAddress(this._privateKey); } public newSignedTransaction( @@ -24,6 +27,7 @@ export class TransactionFactory { signerAddress, data, verifyingContractAddress: this._exchangeAddress, + chainId: this._chainId, }; const transactionHashBuffer = transactionHashUtils.getTransactionHashBuffer(transaction); diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts index a3b26a9724..6c647b9cf2 100644 --- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts @@ -11,7 +11,7 @@ import { OrderValidationUtils, } from '@0x/order-utils'; import { AssetProxyId, Order, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { BlockParamLiteral, ContractAbi, LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; @@ -1239,7 +1239,6 @@ export class ExchangeWrapper extends ContractWrapper { const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider()); await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( exchangeTradeSimulator, - this._web3Wrapper.getProvider(), signedOrder, fillTakerAssetAmount, takerAddress, @@ -1260,8 +1259,9 @@ export class ExchangeWrapper extends ContractWrapper { * @return TransactionEncoder */ public async transactionEncoderAsync(): Promise { + const chainId = await providerUtils.getChainIdAsync(this._web3Wrapper.getProvider()); const exchangeInstance = await this._getExchangeContractAsync(); - const encoder = new TransactionEncoder(exchangeInstance); + const encoder = new TransactionEncoder(exchangeInstance, chainId); return encoder; } // tslint:enable:no-unused-variable diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts index 0832ee73a9..fec9e0a028 100644 --- a/packages/contract-wrappers/src/utils/transaction_encoder.ts +++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts @@ -15,8 +15,11 @@ import { assert } from './assert'; */ export class TransactionEncoder { private readonly _exchangeInstance: ExchangeContract; - constructor(exchangeInstance: ExchangeContract) { + private readonly _chainId: number; + + constructor(exchangeInstance: ExchangeContract, chainId: number) { this._exchangeInstance = exchangeInstance; + this._chainId = chainId; } /** * Hashes the transaction data for use with the Exchange contract. @@ -29,6 +32,7 @@ export class TransactionEncoder { const exchangeAddress = this._getExchangeContract().address; const transaction = { verifyingContractAddress: exchangeAddress, + chainId: this._chainId, salt, signerAddress, data, diff --git a/packages/contract-wrappers/test/calldata_optimization_utils_test.ts b/packages/contract-wrappers/test/calldata_optimization_utils_test.ts index 6cb8a669e3..70430ed81c 100644 --- a/packages/contract-wrappers/test/calldata_optimization_utils_test.ts +++ b/packages/contract-wrappers/test/calldata_optimization_utils_test.ts @@ -14,8 +14,9 @@ const expect = chai.expect; // utility for generating a set of order objects with mostly NULL values // except for a specified makerAssetData and takerAssetData const FAKE_ORDERS_COUNT = 5; +const CHAIN_ID = 1337; const generateFakeOrders = (makerAssetData: string, takerAssetData: string) => - _.map(_.range(FAKE_ORDERS_COUNT), index => { + _.map(_.range(FAKE_ORDERS_COUNT), () => { const order = orderFactory.createOrder( constants.NULL_ADDRESS, constants.ZERO_AMOUNT, @@ -23,6 +24,7 @@ const generateFakeOrders = (makerAssetData: string, takerAssetData: string) => constants.ZERO_AMOUNT, takerAssetData, constants.NULL_ADDRESS, + CHAIN_ID, ); return { ...order, diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts index 278b343a8c..8aa03ad8b9 100644 --- a/packages/order-utils/src/constants.ts +++ b/packages/order-utils/src/constants.ts @@ -136,7 +136,7 @@ export const constants = { ], }, COORDINATOR_DOMAIN_NAME: '0x Protocol Coordinator', - COORDINATOR_DOMAIN_VERSION: '1.0.0', + COORDINATOR_DOMAIN_VERSION: '2.0.0', COORDINATOR_APPROVAL_SCHEMA: { name: 'CoordinatorApproval', parameters: [ diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts index 927dab0733..17f95ce52c 100644 --- a/packages/order-utils/src/eip712_utils.ts +++ b/packages/order-utils/src/eip712_utils.ts @@ -61,6 +61,7 @@ export const eip712Utils = { }); const domain = { verifyingContractAddress: order.exchangeAddress, + chainId: order.chainId, }; const typedData = eip712Utils.createTypedData( constants.EXCHANGE_ORDER_SCHEMA.name, @@ -84,6 +85,7 @@ export const eip712Utils = { }); const domain = { verifyingContractAddress: zeroExTransaction.verifyingContractAddress, + chainId: zeroExTransaction.chainId, }; const typedData = eip712Utils.createTypedData( constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name, diff --git a/packages/order-utils/src/order_factory.ts b/packages/order-utils/src/order_factory.ts index 61da6bacd3..28d6d97730 100644 --- a/packages/order-utils/src/order_factory.ts +++ b/packages/order-utils/src/order_factory.ts @@ -1,5 +1,5 @@ import { Order, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, providerUtils } from '@0x/utils'; import { SupportedProvider } from 'ethereum-types'; import * as _ from 'lodash'; @@ -10,14 +10,18 @@ import { signatureUtils } from './signature_utils'; import { CreateOrderOpts } from './types'; export const orderFactory = { createOrderFromPartial(partialOrder: Partial): Order { - const defaultOrder = generateEmptyOrder(); + if (_.isNil(partialOrder.chainId)) + throw new Error('chainId must be valid'); + const defaultOrder = generateEmptyOrder(partialOrder.chainId); return { ...defaultOrder, ...partialOrder, }; }, createSignedOrderFromPartial(partialSignedOrder: Partial): SignedOrder { - const defaultOrder = generateEmptySignedOrder(); + if (_.isNil(partialSignedOrder.chainId)) + throw new Error('chainId must be valid'); + const defaultOrder = generateEmptySignedOrder(partialSignedOrder.chainId); return { ...defaultOrder, ...partialSignedOrder, @@ -30,6 +34,7 @@ export const orderFactory = { takerAssetAmount: BigNumber, takerAssetData: string, exchangeAddress: string, + chainId: number, createOrderOpts: CreateOrderOpts = generateDefaultCreateOrderOpts(), ): Order { const defaultCreateOrderOpts = generateDefaultCreateOrderOpts(); @@ -48,6 +53,7 @@ export const orderFactory = { salt: createOrderOpts.salt || defaultCreateOrderOpts.salt, expirationTimeSeconds: createOrderOpts.expirationTimeSeconds || defaultCreateOrderOpts.expirationTimeSeconds, + chainId: chainId, }; return order; }, @@ -68,6 +74,7 @@ export const orderFactory = { takerAssetAmount, takerAssetData, exchangeAddress, + await providerUtils.getChainIdAsync(supportedProvider), createOrderOpts, ); const orderHash = orderHashUtils.getOrderHashHex(order); @@ -77,13 +84,13 @@ export const orderFactory = { }, }; -function generateEmptySignedOrder(): SignedOrder { +function generateEmptySignedOrder(chainId: number): SignedOrder { return { - ...generateEmptyOrder(), + ...generateEmptyOrder(chainId), signature: constants.NULL_BYTES, }; } -function generateEmptyOrder(): Order { +function generateEmptyOrder(chainId: number): Order { return { senderAddress: constants.NULL_ADDRESS, makerAddress: constants.NULL_ADDRESS, @@ -96,6 +103,7 @@ function generateEmptyOrder(): Order { takerAssetData: constants.NULL_BYTES, salt: generatePseudoRandomSalt(), exchangeAddress: constants.NULL_ADDRESS, + chainId: chainId, feeRecipientAddress: constants.NULL_ADDRESS, expirationTimeSeconds: constants.INFINITE_TIMESTAMP_SEC, }; diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts index ad8b65cc78..0b9b0d0041 100644 --- a/packages/order-utils/src/order_state_utils.ts +++ b/packages/order-utils/src/order_state_utils.ts @@ -42,6 +42,7 @@ type OrderValidationResult = OrderValidResult | OrderInvalidResult; export class OrderStateUtils { private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher; private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher; + private readonly _chainId: number; private static _validateIfOrderIsValid( signedOrder: SignedOrder, sidedOrderRelevantState: SidedOrderRelevantState, @@ -102,14 +103,17 @@ export class OrderStateUtils { * and proxyAllowances for Ethereum addresses. It must implement AbstractBalanceAndProxyAllowanceFetcher * @param orderFilledCancelledFetcher A class that is capable of fetching whether an order * is cancelled and how much of it has been filled. It must implement AbstractOrderFilledCancelledFetcher + * @param chainId The chain ID of the network being used. * @return Instance of OrderStateUtils */ constructor( balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher, + chainId: number, ) { this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher; this._orderFilledCancelledFetcher = orderFilledCancelledFetcher; + this._chainId = chainId; } /** * Get the orderState for an "open" order (i.e where takerAddress=NULL_ADDRESS) diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts index 1949155b6a..860d37683e 100644 --- a/packages/order-utils/src/order_validation_utils.ts +++ b/packages/order-utils/src/order_validation_utils.ts @@ -227,7 +227,6 @@ export class OrderValidationUtils { /** * Validate a call to FillOrder and throw if it wouldn't succeed * @param exchangeTradeEmulator ExchangeTradeEmulator to use - * @param supportedProvider Web3 provider to use for JSON RPC requests * @param signedOrder SignedOrder of interest * @param fillTakerAssetAmount Amount we'd like to fill the order for * @param takerAddress The taker of the order @@ -235,7 +234,6 @@ export class OrderValidationUtils { */ public async validateFillOrderThrowIfInvalidAsync( exchangeTradeEmulator: ExchangeTransferSimulator, - supportedProvider: SupportedProvider, signedOrder: SignedOrder, fillTakerAssetAmount: BigNumber, takerAddress: string, @@ -247,10 +245,10 @@ export class OrderValidationUtils { if (fillTakerAssetAmount.eq(0)) { throw new Error(RevertReason.InvalidTakerAmount); } - const provider = providerUtils.standardizeOrThrow(supportedProvider); + const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const isValid = await signatureUtils.isValidSignatureAsync( - provider, + this._provider, orderHash, signedOrder.signature, signedOrder.makerAddress, diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index a7d15af313..35aafa1446 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -232,6 +232,7 @@ export const signatureUtils = { if (err.message.includes('User denied message signature')) { throw err; } + const chainId = await providerUtils.getChainIdAsync(supportedProvider); const orderHash = orderHashUtils.getOrderHashHex(order); const signatureHex = await signatureUtils.ecSignHashAsync(supportedProvider, orderHash, signerAddress); const signedOrder = { @@ -255,6 +256,7 @@ export const signatureUtils = { signerAddress: string, ): Promise { const provider = providerUtils.standardizeOrThrow(supportedProvider); + const chainId = await providerUtils.getChainIdAsync(provider); assert.isETHAddressHex('signerAddress', signerAddress); assert.doesConformToSchema('order', order, schemas.orderSchema, [schemas.hexSchema]); const web3Wrapper = new Web3Wrapper(provider); diff --git a/packages/order-utils/test/eip712_utils_test.ts b/packages/order-utils/test/eip712_utils_test.ts index c97bed1447..6ff8febfc5 100644 --- a/packages/order-utils/test/eip712_utils_test.ts +++ b/packages/order-utils/test/eip712_utils_test.ts @@ -11,6 +11,8 @@ chaiSetup.configure(); const expect = chai.expect; describe('EIP712 Utils', () => { + const CHAIN_ID = 1337; + describe('createTypedData', () => { it('adds in the EIP712DomainSeparator with default values', () => { const primaryType = 'Test'; @@ -18,7 +20,7 @@ describe('EIP712 Utils', () => { primaryType, { Test: [{ name: 'testValue', type: 'uint256' }] }, { testValue: '1' }, - { verifyingContractAddress: constants.NULL_ADDRESS }, + { chainId: CHAIN_ID, verifyingContractAddress: constants.NULL_ADDRESS, }, ); expect(typedData.domain).to.not.be.undefined(); expect(typedData.types.EIP712Domain).to.not.be.undefined(); @@ -36,7 +38,12 @@ describe('EIP712 Utils', () => { primaryType, { Test: [{ name: 'testValue', type: 'uint256' }] }, { testValue: '1' }, - { name: domainName, version: domainVersion, verifyingContractAddress: constants.NULL_ADDRESS }, + { + name: domainName, + version: domainVersion, + chainId: CHAIN_ID, + verifyingContractAddress: constants.NULL_ADDRESS, + }, ); expect(typedData.domain).to.not.be.undefined(); expect(typedData.types.EIP712Domain).to.not.be.undefined(); @@ -54,6 +61,7 @@ describe('EIP712 Utils', () => { data: constants.NULL_BYTES, signerAddress: constants.NULL_ADDRESS, verifyingContractAddress: constants.NULL_ADDRESS, + chainId: CHAIN_ID, }); expect(typedData.primaryType).to.eq(constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name); expect(typedData.types.EIP712Domain).to.not.be.undefined(); diff --git a/packages/order-utils/test/order_hash_test.ts b/packages/order-utils/test/order_hash_test.ts index 514fc27099..a4c7de2d9a 100644 --- a/packages/order-utils/test/order_hash_test.ts +++ b/packages/order-utils/test/order_hash_test.ts @@ -14,8 +14,9 @@ const expect = chai.expect; describe('Order hashing', () => { describe('#getOrderHashHex', () => { - const expectedOrderHash = '0x434c6b41e2fb6dfcfe1b45c4492fb03700798e9c1afc6f801ba6203f948c1fa7'; + const expectedOrderHash = '0x2af69ce573fc9ffc734c88aaafc6907e2619572a462ca1ab2326e0e4bebec127'; const fakeExchangeContractAddress = '0x1dc4c1cefef38a777b15aa20260a54e584b16c48'; + const fakeChainID = 1337; const order: Order = { makerAddress: constants.NULL_ADDRESS, takerAddress: constants.NULL_ADDRESS, @@ -24,6 +25,7 @@ describe('Order hashing', () => { makerAssetData: constants.NULL_ADDRESS, takerAssetData: constants.NULL_ADDRESS, exchangeAddress: fakeExchangeContractAddress, + chainId: fakeChainID, salt: new BigNumber(0), makerFee: new BigNumber(0), takerFee: new BigNumber(0), diff --git a/packages/order-utils/test/order_state_utils_test.ts b/packages/order-utils/test/order_state_utils_test.ts index 42acd54c6f..b5fbd6f87f 100644 --- a/packages/order-utils/test/order_state_utils_test.ts +++ b/packages/order-utils/test/order_state_utils_test.ts @@ -14,6 +14,8 @@ chaiSetup.configure(); const expect = chai.expect; describe('OrderStateUtils', () => { + const CHAIN_ID = 1337; + describe('#getOpenOrderStateAsync', () => { const buildMockBalanceFetcher = (takerBalance: BigNumber): AbstractBalanceAndProxyAllowanceFetcher => { const balanceFetcher = { @@ -58,7 +60,11 @@ describe('OrderStateUtils', () => { 1, ); - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderStateUtils = new OrderStateUtils( + mockBalanceFetcher, + mockOrderFilledFetcher, + CHAIN_ID, + ); const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); expect(orderState.isValid).to.eq(true); }); @@ -77,7 +83,11 @@ describe('OrderStateUtils', () => { 1, ); - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderStateUtils = new OrderStateUtils( + mockBalanceFetcher, + mockOrderFilledFetcher, + CHAIN_ID, + ); const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); expect(orderState.isValid).to.eq(false); }); @@ -97,7 +107,11 @@ describe('OrderStateUtils', () => { 1, ); - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderStateUtils = new OrderStateUtils( + mockBalanceFetcher, + mockOrderFilledFetcher, + CHAIN_ID, + ); const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); expect(orderState.isValid).to.eq(false); }); @@ -117,7 +131,11 @@ describe('OrderStateUtils', () => { 1, ); - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderStateUtils = new OrderStateUtils( + mockBalanceFetcher, + mockOrderFilledFetcher, + CHAIN_ID, + ); const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); expect(orderState.isValid).to.eq(false); }); @@ -136,7 +154,11 @@ describe('OrderStateUtils', () => { 1, ); - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderStateUtils = new OrderStateUtils( + mockBalanceFetcher, + mockOrderFilledFetcher, + CHAIN_ID, + ); const transactionHash = '0xdeadbeef'; const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash); expect(orderState.transactionHash).to.eq(transactionHash); diff --git a/packages/order-utils/test/remaining_fillable_calculator_test.ts b/packages/order-utils/test/remaining_fillable_calculator_test.ts index affad8f1cb..16143dc60b 100644 --- a/packages/order-utils/test/remaining_fillable_calculator_test.ts +++ b/packages/order-utils/test/remaining_fillable_calculator_test.ts @@ -43,6 +43,7 @@ describe('RemainingFillableCalculator', () => { return { signature, exchangeAddress: zeroAddress, + chainId: 1337, feeRecipientAddress: zeroAddress, senderAddress: zeroAddress, makerAddress: zeroAddress, diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts index 1c6db80232..8f5932aee9 100644 --- a/packages/order-utils/test/signature_utils_test.ts +++ b/packages/order-utils/test/signature_utils_test.ts @@ -20,6 +20,7 @@ const expect = chai.expect; describe('Signature utils', () => { let makerAddress: string; const fakeExchangeContractAddress = '0x1dc4c1cefef38a777b15aa20260a54e584b16c48'; + const CHAIN_ID = 1337; let order: Order; let transaction: ZeroExTransaction; before(async () => { @@ -33,6 +34,7 @@ describe('Signature utils', () => { makerAssetData: constants.NULL_ADDRESS, takerAssetData: constants.NULL_ADDRESS, exchangeAddress: fakeExchangeContractAddress, + chainId: CHAIN_ID, salt: new BigNumber(0), makerFee: new BigNumber(0), takerFee: new BigNumber(0), @@ -160,7 +162,7 @@ describe('Signature utils', () => { describe('#ecSignOrderAsync', () => { it('should default to eth_sign if eth_signTypedData is unavailable', async () => { const expectedSignature = - '0x1c3582f06356a1314dbf1c0e534c4d8e92e59b056ee607a7ff5a825f5f2cc5e6151c5cc7fdd420f5608e4d5bef108e42ad90c7a4b408caef32e24374cf387b0d7603'; + '0x1bcbeb571648db1b7e0454175a6a4b4da1ac07cfc5fb5e4c8e4e10aa4aad368a11050ac85be1ca543eb4e1c07b852cbe6619cbab0cbbf05df364d80e126ffe731403'; const fakeProvider = { async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { @@ -356,7 +358,7 @@ describe('Signature utils', () => { }); it('should return the correct Signature for signatureHex concatenated as R + S + V', async () => { const expectedSignature = - '0x1cd472c439833774b55d248c31b6585f21aea1b9363ebb4ec58549e46b62eb5a6f696f5781f62de008ee7f77650ef940d99c97ec1dee67b3f5cea1bbfdfeb2eba602'; + '0x1baf6c2d23afb5389e29e4274e3dc419939641e94f56a62260a004f2f79b9501c725a1d740c75d1f6e0bdc7b158c62e1ec36b7e9a16086f249fd821fa00d5652db02'; const fakeProvider = { async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { if (payload.method === 'eth_signTypedData') { diff --git a/packages/order-utils/test/transaction_hash_test.ts b/packages/order-utils/test/transaction_hash_test.ts index c7ca33a643..c2fcd6225c 100644 --- a/packages/order-utils/test/transaction_hash_test.ts +++ b/packages/order-utils/test/transaction_hash_test.ts @@ -14,10 +14,11 @@ const expect = chai.expect; describe('0x transaction hashing', () => { describe('#getTransactionHashHex', () => { - const expectedTransactionHash = '0x82c9bb2dcac4f868ec7a15c20ff6175cfc384c20ae6a872aa0342a840f108c2b'; + const expectedTransactionHash = '0xbd640f97452817179076e736257ea85feac51530f1844ef05297af69e375522b'; const fakeVerifyingContractAddress = '0x5e72914535f202659083db3a02c984188fa26e9f'; const transaction: ZeroExTransaction = { verifyingContractAddress: fakeVerifyingContractAddress, + chainId: 1337, signerAddress: constants.NULL_ADDRESS, salt: new BigNumber(0), data: constants.NULL_BYTES, diff --git a/packages/order-utils/test/utils/test_order_factory.ts b/packages/order-utils/test/utils/test_order_factory.ts index 4efe0b38ee..4f5c6b453f 100644 --- a/packages/order-utils/test/utils/test_order_factory.ts +++ b/packages/order-utils/test/utils/test_order_factory.ts @@ -11,6 +11,7 @@ const BASE_TEST_ORDER: Order = orderFactory.createOrder( constants.ZERO_AMOUNT, constants.NULL_ERC20_ASSET_DATA, constants.NULL_ADDRESS, + 0, ); const BASE_TEST_SIGNED_ORDER: SignedOrder = { ...BASE_TEST_ORDER, diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 96e061ade8..44e59c5fff 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -18,6 +18,7 @@ export interface Order { takerAssetData: string; salt: BigNumber; exchangeAddress: string; + chainId: number; feeRecipientAddress: string; expirationTimeSeconds: BigNumber; } @@ -51,6 +52,7 @@ export enum MarketOperation { */ export interface ZeroExTransaction { verifyingContractAddress: string; + chainId: number; salt: BigNumber; signerAddress: string; data: string; diff --git a/packages/utils/src/provider_utils.ts b/packages/utils/src/provider_utils.ts index 7ed74b8899..ce20d16a07 100644 --- a/packages/utils/src/provider_utils.ts +++ b/packages/utils/src/provider_utils.ts @@ -2,6 +2,7 @@ import { EIP1193Provider, JSONRPCErrorCallback, JSONRPCRequestPayload, + JSONRPCResponsePayload, SupportedProvider, ZeroExProvider, } from 'ethereum-types'; @@ -94,4 +95,30 @@ export const providerUtils = { `Unsupported provider found. Please make sure it conforms to one of the supported providers. See 'Provider' type in 'ethereum-types' package.`, ); }, + + /** + * Retrieve the chain ID from a supported provider. + * @param supportedProvider A supported provider instance. + * @return A promise thar resolves to the chain ID of the network the provider + * is connected to. + */ + async getChainIdAsync(supportedProvider: SupportedProvider): Promise { + const provider = this.standardizeOrThrow(supportedProvider); + return new Promise((accept, reject) => { + provider.sendAsync({ + jsonrpc: '2.0', + id: _.random(0, 2**64), + method: 'net_version', + params: [] + }, + (err : Error | null, result?: JSONRPCResponsePayload) => { + if (!_.isNil(err)) + reject(err); + if (!result) + throw new Error('Invalid \'net_version\' response'); + accept(_.toNumber(result.result)); + } + ); + }); + }, }; diff --git a/packages/utils/src/sign_typed_data_utils.ts b/packages/utils/src/sign_typed_data_utils.ts index adb66622d0..87df3d816e 100644 --- a/packages/utils/src/sign_typed_data_utils.ts +++ b/packages/utils/src/sign_typed_data_utils.ts @@ -71,8 +71,13 @@ export const signTypedDataUtils = { return ethers.utils.defaultAbiCoder.encode(encodedTypes, encodedValues); }, _normalizeValue(type: string, value: any): EIP712ObjectValue { - const normalizedValue = type === 'uint256' && BigNumber.isBigNumber(value) ? value.toString() : value; - return normalizedValue; + if (type == 'uint256') { + if (BigNumber.isBigNumber(value)) { + return value.toString(10); + } + return new BigNumber(value).toString(10); + } + return value; }, _typeHash(primaryType: string, types: EIP712Types): Buffer { return ethUtil.sha3(signTypedDataUtils._encodeType(primaryType, types)); diff --git a/packages/utils/test/sign_typed_data_utils_test.ts b/packages/utils/test/sign_typed_data_utils_test.ts index 3d2cb2496c..0bccab1f96 100644 --- a/packages/utils/test/sign_typed_data_utils_test.ts +++ b/packages/utils/test/sign_typed_data_utils_test.ts @@ -36,7 +36,7 @@ describe('signTypedDataUtils', () => { }, primaryType: 'Test', }; - const orderSignTypedDataHashHex = '0x55eaa6ec02f3224d30873577e9ddd069a288c16d6fb407210eecbc501fa76692'; + const orderSignTypedDataHashHex = '0x78772b297e1b0b31089589a6608930cceba855af9d3ccf7b92cf47fa881e21f7'; const orderSignTypedData = { types: { EIP712Domain: [ @@ -48,6 +48,10 @@ describe('signTypedDataUtils', () => { name: 'version', type: 'string', }, + { + name: 'chainId', + type: 'uint256', + }, { name: 'verifyingContract', type: 'address', @@ -107,6 +111,7 @@ describe('signTypedDataUtils', () => { domain: { name: '0x Protocol', version: '2', + chainId: 1337, verifyingContract: '0x0000000000000000000000000000000000000000', }, message: { @@ -157,7 +162,7 @@ describe('signTypedDataUtils', () => { }; const hash = signTypedDataUtils.generateTypedDataHash(uninitializedOrder).toString('hex'); const hashHex = `0x${hash}`; - expect(hashHex).to.be.eq('0xfaa49b35faeb9197e9c3ba7a52075e6dad19739549f153b77dfcf59408a4b422'); + expect(hashHex).to.be.eq('0x510449a190415c4770080d857a1c654b653a0c054c94a7a8e9f08f623f9e824f'); }); }); });