diff --git a/contracts/core/extensions/CoreIssuanceOrder.sol b/contracts/core/extensions/CoreIssuanceOrder.sol index 36f3b6404..dd410ef56 100644 --- a/contracts/core/extensions/CoreIssuanceOrder.sol +++ b/contracts/core/extensions/CoreIssuanceOrder.sol @@ -18,11 +18,13 @@ pragma solidity 0.4.24; pragma experimental "ABIEncoderV2"; +import { Math } from "zeppelin-solidity/contracts/math/Math.sol"; import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol"; import { CoreModifiers } from "../lib/CoreSharedModifiers.sol"; import { CoreState } from "../lib/CoreState.sol"; import { ExchangeHandler } from "../lib/ExchangeHandler.sol"; import { ICoreIssuance } from "../interfaces/ICoreIssuance.sol"; +import { ISetToken } from "../interfaces/ISetToken.sol"; import { LibBytes } from "../../external/LibBytes.sol"; import { OrderLibrary } from "../lib/OrderLibrary.sol"; @@ -41,15 +43,18 @@ contract CoreIssuanceOrder is CoreModifiers { using SafeMath for uint256; + using Math for uint256; /* ============ Constants ============ */ uint256 constant HEADER_LENGTH = 64; - string constant INVALID_EXCHANGE = "Exchange does not exist."; string constant INVALID_CANCEL_ORDER = "Only maker can cancel order."; + string constant INVALID_EXCHANGE = "Exchange does not exist."; + string constant INVALID_FILL_AMOUNT = "Fill amount must be equal or less than open order amount."; + string constant INVALID_QUANTITY = "Quantity must be multiple of the natural unit of the set."; string constant INVALID_SIGNATURE = "Invalid order signature."; - string constant INVALID_TOKEN_AMOUNTS = "Quantity and makerTokenAmount should be greater than 0."; + string constant POSITIVE_AMOUNT_REQUIRED = "Quantity should be greater than 0."; string constant ORDER_EXPIRED = "This order has expired."; /* ============ External Functions ============ */ @@ -57,27 +62,24 @@ contract CoreIssuanceOrder is /** * Fill an issuance order * - * @param _addresses [setAddress, makerAddress, makerToken, relayerToken] + * @param _addresses [setAddress, makerAddress, makerToken, relayerAddress, relayerToken] * @param _values [quantity, makerTokenAmount, expiration, relayerTokenAmount, salt] * @param _fillQuantity Quantity of set to be filled * @param _v v element of ECDSA signature - * @param _r r element of ECDSA signature - * @param _s s element of ECDSA signature + * @param sigBytes Array with r and s segments of ECDSA signature * @param _orderData Bytes array containing the exchange orders to execute */ function fillOrder( - address[4] _addresses, + address[5] _addresses, uint[5] _values, uint _fillQuantity, uint8 _v, - bytes32 _r, - bytes32 _s, + bytes32[] sigBytes, bytes _orderData ) external isValidSet(_addresses[0]) isPositiveQuantity(_fillQuantity) - isNaturalUnitMultiple(_fillQuantity, _addresses[0]) { OrderLibrary.IssuanceOrder memory order = OrderLibrary.IssuanceOrder({ setAddress: _addresses[0], @@ -86,7 +88,8 @@ contract CoreIssuanceOrder is makerToken: _addresses[2], makerTokenAmount: _values[1], expiration: _values[2], - relayerToken: _addresses[3], + relayerAddress: _addresses[3], + relayerToken: _addresses[4], relayerTokenAmount: _values[3], salt: _values[4], orderHash: OrderLibrary.generateOrderHash( @@ -95,28 +98,35 @@ contract CoreIssuanceOrder is ) }); - // Verify order is valid and return amount to be filled - validateOrder( - order, - _fillQuantity - ); - // Verify signature is authentic require( OrderLibrary.validateSignature( order.orderHash, order.makerAddress, _v, - _r, - _s + sigBytes[0], // r + sigBytes[1] // s ), INVALID_SIGNATURE ); + // Verify order is valid and return amount to be filled + validateOrder( + order, + _fillQuantity + ); + // Execute exchange orders executeExchangeOrders(_orderData); - // TO DO: When openOrder amount functionality added these must change + // Check to make sure open order amount equals _fillQuantity + uint closedOrderAmount = state.orderFills[order.orderHash].add(state.orderCancels[order.orderHash]); + uint openOrderAmount = order.quantity.sub(closedOrderAmount); + require( + openOrderAmount >= _fillQuantity, + INVALID_FILL_AMOUNT + ); + // Tally fill in orderFills mapping state.orderFills[order.orderHash] = state.orderFills[order.orderHash].add(_fillQuantity); @@ -131,12 +141,12 @@ contract CoreIssuanceOrder is /** * Cancel an issuance order * - * @param _addresses [setAddress, makerAddress, makerToken, relayerToken] + * @param _addresses [setAddress, makerAddress, makerToken, relayerAddress, relayerToken] * @param _values [quantity, makerTokenAmount, expiration, relayerTokenAmount, salt] * @param _cancelQuantity Quantity of set to be filled */ function cancelOrder( - address[4] _addresses, + address[5] _addresses, uint[5] _values, uint _cancelQuantity ) @@ -150,7 +160,8 @@ contract CoreIssuanceOrder is makerToken: _addresses[2], makerTokenAmount: _values[1], expiration: _values[2], - relayerToken: _addresses[3], + relayerAddress: _addresses[3], + relayerToken: _addresses[4], relayerTokenAmount: _values[3], salt: _values[4], orderHash: OrderLibrary.generateOrderHash( @@ -162,15 +173,19 @@ contract CoreIssuanceOrder is // Make sure cancel order comes from maker require(order.makerAddress == msg.sender, INVALID_CANCEL_ORDER); - // Verify order is valid and return amount to be cancelled + // Verify order is valid validateOrder( order, _cancelQuantity ); - // TO DO: When openOrder amount functionality added these must change + // Determine amount to cancel + uint closedOrderAmount = state.orderFills[order.orderHash].add(state.orderCancels[order.orderHash]); + uint openOrderAmount = order.quantity.sub(closedOrderAmount); + uint canceledAmount = openOrderAmount.min256(_cancelQuantity); + // Tally cancel in orderCancels mapping - state.orderCancels[order.orderHash] = state.orderCancels[order.orderHash].add(_cancelQuantity); + state.orderCancels[order.orderHash] = state.orderCancels[order.orderHash].add(canceledAmount); } /* ============ Private Functions ============ */ @@ -225,11 +240,11 @@ contract CoreIssuanceOrder is * Validate order params are still valid * * @param _order IssuanceOrder object containing order params - * @param _fillQuantity Quantity of Set to be filled + * @param _executeQuantity Quantity of Set to be filled */ function validateOrder( OrderLibrary.IssuanceOrder _order, - uint _fillQuantity + uint _executeQuantity ) private view @@ -237,14 +252,24 @@ contract CoreIssuanceOrder is // Make sure makerTokenAmount and Set Token to issue is greater than 0. require( _order.makerTokenAmount > 0 && _order.quantity > 0, - INVALID_TOKEN_AMOUNTS + POSITIVE_AMOUNT_REQUIRED ); // Make sure the order hasn't expired require( block.timestamp <= _order.expiration, ORDER_EXPIRED ); - // TO DO: Check to make sure quantity is multiple of natural unit - // TO DO: Check to see if filled + + // Make sure IssuanceOrder quantity is multiple of natural unit + require( + _order.quantity % ISetToken(_order.setAddress).naturalUnit() == 0, + INVALID_QUANTITY + ); + + // Make sure fill or cancel quantity is multiple of natural unit + require( + _executeQuantity % ISetToken(_order.setAddress).naturalUnit() == 0, + INVALID_QUANTITY + ); } } diff --git a/contracts/core/lib/OrderLibrary.sol b/contracts/core/lib/OrderLibrary.sol index d08723e32..3976d9b6a 100644 --- a/contracts/core/lib/OrderLibrary.sol +++ b/contracts/core/lib/OrderLibrary.sol @@ -36,7 +36,8 @@ library OrderLibrary { address makerToken; // _addresses[2] uint256 makerTokenAmount; // _values[1] uint256 expiration; // _values[2] - address relayerToken; // _addresses[3] + address relayerAddress; // _addresses[3] + address relayerToken; // _addresses[4] uint256 relayerTokenAmount; // _values[3] uint256 salt; // _values[4] bytes32 orderHash; @@ -47,11 +48,11 @@ library OrderLibrary { /** * Create hash of order parameters * - * @param _addresses [setAddress, makerAddress, makerToken, relayerToken] + * @param _addresses [setAddress, makerAddress, makerToken, relayerAddress, relayerToken] * @param _values [quantity, makerTokenAmount, expiration, relayerTokenAmount, salt] */ function generateOrderHash( - address[4] _addresses, + address[5] _addresses, uint[5] _values ) internal @@ -64,7 +65,8 @@ library OrderLibrary { _addresses[0], // setAddress _addresses[1], // makerAddress _addresses[2], // makerToken - _addresses[3], // relayerToken + _addresses[3], // relayerAddress + _addresses[4], // relayerToken _values[0], // quantity _values[1], // makerTokenAmount _values[2], // expiration diff --git a/contracts/test/lib/MockOrderLibrary.sol b/contracts/test/lib/MockOrderLibrary.sol index e4aa74c40..f73cd440c 100644 --- a/contracts/test/lib/MockOrderLibrary.sol +++ b/contracts/test/lib/MockOrderLibrary.sol @@ -6,7 +6,7 @@ import { OrderLibrary } from "../../core/lib/OrderLibrary.sol"; // Mock contract implementation of OrderLibrary functions contract MockOrderLibrary { function testGenerateOrderHash( - address[4] _addresses, + address[5] _addresses, uint[5] _values ) public diff --git a/test/core/extensions/coreIssuanceOrder.spec.ts b/test/core/extensions/coreIssuanceOrder.spec.ts index c9a31e00b..afe7b84be 100644 --- a/test/core/extensions/coreIssuanceOrder.spec.ts +++ b/test/core/extensions/coreIssuanceOrder.spec.ts @@ -56,6 +56,7 @@ contract("CoreIssuanceOrder", (accounts) => { takerAccount, makerAccount, signerAccount, + relayerAccount, mockSetTokenAccount, mockTokenAccount ] = accounts; @@ -93,16 +94,21 @@ contract("CoreIssuanceOrder", (accounts) => { let components: StandardTokenMockContract[] = []; let componentUnits: BigNumber[]; let setToken: SetTokenContract; + + let setAddress: Address; + let makerAddress: Address; let signerAddress: Address; + let relayerAddress: Address; let componentAddresses: Address[]; + let orderQuantity: BigNumber; + let makerTokenAmount: BigNumber; + let timeToExpiration: number; let issuanceOrderParams: any; beforeEach(async () => { - signerAddress = signerAccount; - - components = await erc20Wrapper.deployTokensAsync(2, signerAddress); //For current purposes issue to maker/signer - await erc20Wrapper.approveTransfersAsync(components, transferProxy.address, signerAddress); + components = await erc20Wrapper.deployTokensAsync(2, signerAccount); //For current purposes issue to maker/signer + await erc20Wrapper.approveTransfersAsync(components, transferProxy.address, signerAccount); componentAddresses = _.map(components, (token) => token.address); componentUnits = _.map(components, () => ether(4)); // Multiple of naturalUnit @@ -115,11 +121,22 @@ contract("CoreIssuanceOrder", (accounts) => { ); await coreWrapper.registerDefaultExchanges(core); + relayerAddress = relayerAccount; + + issuanceOrderParams = await generateFillOrderParameters( + setAddress || setToken.address, + signerAddress || signerAccount, + makerAddress || signerAccount, + componentAddresses[0], + relayerAddress, + orderQuantity || ether(4), + makerTokenAmount || ether(10), + timeToExpiration || 10, + ); - subjectCaller = takerAccount; - subjectQuantityToIssue = ether(2); - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0]); subjectExchangeOrdersData = generateOrdersDataForOrderCount(3); + subjectCaller = takerAccount; + subjectQuantityToIssue = ether(4); }); async function subject(): Promise { @@ -128,32 +145,41 @@ contract("CoreIssuanceOrder", (accounts) => { issuanceOrderParams.values, subjectQuantityToIssue, issuanceOrderParams.signature.v, - issuanceOrderParams.signature.r, - issuanceOrderParams.signature.s, + [issuanceOrderParams.signature.r, issuanceOrderParams.signature.s], subjectExchangeOrdersData, { from: subjectCaller }, ); } + afterEach(async () => { + setAddress = undefined; + signerAddress = undefined; + makerAddress = undefined; + orderQuantity = undefined; + makerTokenAmount = undefined; + timeToExpiration = undefined; + }); + it("transfers the required tokens from the user", async () => { const component: StandardTokenMockContract = _.first(components); const unit: BigNumber = _.first(componentUnits); - const existingBalance = await component.balanceOf.callAsync(signerAddress); - assertTokenBalance(component, DEPLOYED_TOKEN_QUANTITY, signerAddress); + const existingBalance = await component.balanceOf.callAsync(signerAccount); + assertTokenBalance(component, DEPLOYED_TOKEN_QUANTITY, signerAccount); + await subject(); - const newBalance = await component.balanceOf.callAsync(signerAddress); + const newBalance = await component.balanceOf.callAsync(signerAccount); const expectedNewBalance = existingBalance.sub(subjectQuantityToIssue.div(naturalUnit).mul(unit)); expect(newBalance).to.be.bignumber.equal(expectedNewBalance); }); it("mints the correct quantity of the set for the user", async () => { - const existingBalance = await setToken.balanceOf.callAsync(signerAddress); + const existingBalance = await setToken.balanceOf.callAsync(signerAccount); await subject(); - assertTokenBalance(setToken, existingBalance.add(subjectQuantityToIssue), signerAddress); + assertTokenBalance(setToken, existingBalance.add(subjectQuantityToIssue), signerAccount); }); it("marks the correct amount as filled in orderFills mapping", async () => { @@ -166,6 +192,72 @@ contract("CoreIssuanceOrder", (accounts) => { expect(filled).to.be.bignumber.equal(subjectQuantityToIssue); }); + describe("when the fill size is less than the order quantity", async () => { + beforeEach(async () => { + subjectQuantityToIssue = ether(2); + }); + + it("mints the correct quantity of the set for the user", async () => { + const existingBalance = await setToken.balanceOf.callAsync(signerAccount); + + await subject(); + + assertTokenBalance(setToken, existingBalance.add(subjectQuantityToIssue), signerAccount); + }); + + it("marks the correct amount as filled in orderFills mapping", async () => { + const preFilled = await core.orderFills.callAsync(issuanceOrderParams.orderHash); + expect(preFilled).to.be.bignumber.equal(ZERO); + + await subject(); + + const filled = await core.orderFills.callAsync(issuanceOrderParams.orderHash); + expect(filled).to.be.bignumber.equal(subjectQuantityToIssue); + }); + }); + + describe("when the full fill size has been taken", async () => { + beforeEach(async () => { + const quantityToCancel = ether(4); + await core.cancelOrder.sendTransactionAsync( + issuanceOrderParams.addresses, + issuanceOrderParams.values, + quantityToCancel, + { from: signerAccount } + ); + }); + + it("should revert", async () => { + await expectRevertError(subject()); + }); + }); + + describe("when the partial fill size has been taken", async () => { + beforeEach(async () => { + const quantityToCancel = ether(2); + await core.cancelOrder.sendTransactionAsync( + issuanceOrderParams.addresses, + issuanceOrderParams.values, + quantityToCancel, + { from: signerAccount } + ); + }); + + it("should revert", async () => { + await expectRevertError(subject()); + }); + }); + + describe("when the fill size is greater than the order quantity", async () => { + beforeEach(async () => { + subjectQuantityToIssue = ether(6); + }); + + it("should revert", async () => { + await expectRevertError(subject()); + }); + }); + describe("when the quantity to issue is not positive", async () => { beforeEach(async () => { subjectQuantityToIssue = ZERO; @@ -177,8 +269,8 @@ contract("CoreIssuanceOrder", (accounts) => { }); describe("when the set was not created through core", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(NULL_ADDRESS, signerAddress, signerAddress, componentAddresses[0]) + before(async () => { + setAddress = NULL_ADDRESS; }); it("should revert", async () => { @@ -186,7 +278,7 @@ contract("CoreIssuanceOrder", (accounts) => { }); }); - describe("when the quantity is not a multiple of the natural unit of the set", async () => { + describe("when the fill quantity is not a multiple of the natural unit of the set", async () => { beforeEach(async () => { subjectQuantityToIssue = ether(3); }); @@ -196,9 +288,19 @@ contract("CoreIssuanceOrder", (accounts) => { }); }); + describe("when the order quantity is not a multiple of the natural unit of the set", async () => { + before(async () => { + orderQuantity = ether(5); + }); + + it("should revert", async () => { + await expectRevertError(subject()); + }); + }); + describe("when the order has expired", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0], undefined, undefined, -1) + before(async () => { + timeToExpiration = -1; }); it("should revert", async () => { @@ -206,9 +308,9 @@ contract("CoreIssuanceOrder", (accounts) => { }); }); - describe("when invalid Set Token quantity in Issuance Order", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0], ZERO) + describe("when Set Token quantity in Issuance Order equals 0", async () => { + before(async () => { + orderQuantity = ZERO; }); it("should revert", async () => { @@ -216,9 +318,9 @@ contract("CoreIssuanceOrder", (accounts) => { }); }); - describe("when invalid makerTokenAmount in Issuance Order", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0], undefined, ZERO) + describe("when makerTokenAmount in Issuance Order equals 0", async () => { + before(async () => { + makerTokenAmount = ZERO; }); it("should revert", async () => { @@ -227,8 +329,8 @@ contract("CoreIssuanceOrder", (accounts) => { }); describe("when the message is not signed by the maker", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, makerAccount, componentAddresses[0]); + before(async () => { + makerAddress = makerAccount; }); it("should revert", async () => { @@ -252,24 +354,28 @@ contract("CoreIssuanceOrder", (accounts) => { let subjectQuantityToCancel: BigNumber; let subjectExchangeOrdersData: Bytes32; - const naturalUnit: BigNumber = ether(2); - let components: StandardTokenMockContract[] = []; - let componentUnits: BigNumber[]; - let setToken: SetTokenContract; + let setAddress: Address; + let makerAddress: Address; let signerAddress: Address; + let relayerAddress: Address; let componentAddresses: Address[]; + let orderQuantity: BigNumber; + let makerTokenAmount: BigNumber; + let timeToExpiration: number; let issuanceOrderParams: any; beforeEach(async () => { + const naturalUnit = ether(2); signerAddress = signerAccount; + relayerAddress = relayerAccount; - components = await erc20Wrapper.deployTokensAsync(2, signerAddress); //For current purposes issue to maker/signer + const components = await erc20Wrapper.deployTokensAsync(2, signerAddress); //For current purposes issue to maker/signer await erc20Wrapper.approveTransfersAsync(components, transferProxy.address, signerAddress); componentAddresses = _.map(components, (token) => token.address); - componentUnits = _.map(components, () => ether(4)); // Multiple of naturalUnit - setToken = await coreWrapper.createSetTokenAsync( + const componentUnits = _.map(components, () => ether(4)); // Multiple of naturalUnit + const setToken = await coreWrapper.createSetTokenAsync( core, setTokenFactory.address, componentAddresses, @@ -281,8 +387,16 @@ contract("CoreIssuanceOrder", (accounts) => { subjectCaller = signerAccount; subjectQuantityToCancel = ether(2); - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0]); - subjectExchangeOrdersData = generateOrdersDataForOrderCount(3); + issuanceOrderParams = await generateFillOrderParameters( + setAddress || setToken.address, + signerAddress || signerAccount, + makerAddress || signerAccount, + componentAddresses[0], + relayerAddress, + orderQuantity || ether(4), + makerTokenAmount || ether(10), + timeToExpiration || 10, + ); }); async function subject(): Promise { @@ -294,6 +408,15 @@ contract("CoreIssuanceOrder", (accounts) => { ); } + afterEach(async () => { + setAddress = undefined; + signerAddress = undefined; + makerAddress = undefined; + orderQuantity = undefined; + makerTokenAmount = undefined; + timeToExpiration = undefined; + }); + it("marks the correct amount as canceled in orderCancels mapping", async () => { const preCanceled = await core.orderCancels.callAsync(issuanceOrderParams.orderHash); expect(preCanceled).to.be.bignumber.equal(ZERO); @@ -304,6 +427,23 @@ contract("CoreIssuanceOrder", (accounts) => { expect(canceled).to.be.bignumber.equal(subjectQuantityToCancel); }); + describe("when the quantity to cancel is greater than the open amount", async () => { + beforeEach(async () => { + subjectQuantityToCancel = ether(6); + }); + + it("should mark only the remaining open amount as canceled", async () => { + const filled = await core.orderFills.callAsync(issuanceOrderParams.orderHash); + const preCanceled = await core.orderCancels.callAsync(issuanceOrderParams.orderHash); + const openAmount = issuanceOrderParams.values[0].minus(filled).minus(preCanceled); + + await subject(); + + const canceled = await core.orderCancels.callAsync(issuanceOrderParams.orderHash); + expect(canceled).to.be.bignumber.equal(preCanceled + openAmount); + }); + }); + describe("when the quantity to cancel is not positive", async () => { beforeEach(async () => { subjectQuantityToCancel = ZERO; @@ -325,8 +465,8 @@ contract("CoreIssuanceOrder", (accounts) => { }); describe("when the order has expired", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0], undefined, undefined, -1) + before(async () => { + timeToExpiration = -1; }); it("should revert", async () => { @@ -334,9 +474,9 @@ contract("CoreIssuanceOrder", (accounts) => { }); }); - describe("when invalid Set Token quantity in Issuance Order", async () => { + describe("when the cancel quantity is not a multiple of the natural unit of the set", async () => { beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0], ZERO) + subjectQuantityToCancel = ether(3); }); it("should revert", async () => { @@ -344,9 +484,29 @@ contract("CoreIssuanceOrder", (accounts) => { }); }); - describe("when invalid makerTokenAmount in Issuance Order", async () => { - beforeEach(async () => { - issuanceOrderParams = await generateFillOrderParameters(setToken.address, signerAddress, signerAddress, componentAddresses[0], undefined, ZERO) + describe("when the Set Token quantity in Issuance Order is not a multiple of the natural unit of the set", async () => { + before(async () => { + orderQuantity = ether(5); + }); + + it("should revert", async () => { + await expectRevertError(subject()); + }); + }); + + describe("when Set Token quantity in Issuance Order equals 0", async () => { + before(async () => { + orderQuantity = ZERO; + }); + + it("should revert", async () => { + await expectRevertError(subject()); + }); + }); + + describe("when makerTokenAmount in Issuance Order equals 0", async () => { + before(async () => { + makerTokenAmount = ZERO; }); it("should revert", async () => { diff --git a/test/core/lib/orderLibrary.spec.ts b/test/core/lib/orderLibrary.spec.ts index 158373c0c..ca151010f 100644 --- a/test/core/lib/orderLibrary.spec.ts +++ b/test/core/lib/orderLibrary.spec.ts @@ -42,6 +42,7 @@ contract("OrderLibrary", (accounts) => { takerAccount, makerAccount, signerAccount, + relayerAccount, mockSetTokenAccount, mockTokenAccount ] = accounts; @@ -58,16 +59,32 @@ contract("OrderLibrary", (accounts) => { let subjectCaller: Address; let subjectMaker: Address; let signerAddress: Address; - + let relayerAddress: Address; + let orderQuantity: BigNumber; + let makerTokenAmount: BigNumber; + let timeToExpiration: number; let issuanceOrderParams: any; beforeEach(async () => { - subjectCaller = takerAccount; subjectMaker = signerAccount; - signerAddress = signerAccount; - issuanceOrderParams = await generateFillOrderParameters(mockSetTokenAccount, signerAddress, signerAddress, mockTokenAccount); + signerAddress = signerAccount; + relayerAddress = relayerAccount; + orderQuantity = ether(4); + makerTokenAmount = ether(10); + timeToExpiration = 10; + + issuanceOrderParams = await generateFillOrderParameters( + mockSetTokenAccount, + signerAddress, + signerAddress, + mockTokenAccount, + relayerAddress, + orderQuantity, + makerTokenAmount, + timeToExpiration, + ); }); async function subject(): Promise { @@ -101,12 +118,33 @@ contract("OrderLibrary", (accounts) => { describe("#generateOrderHash", async () => { let subjectCaller: Address; + let signerAddress: Address; + let relayerAddress: Address; + let orderQuantity: BigNumber; + let makerTokenAmount: BigNumber; + let timeToExpiration: number; + let issuanceOrderParams: any; beforeEach(async () => { subjectCaller = takerAccount; - issuanceOrderParams = await generateFillOrderParameters(mockSetTokenAccount, makerAccount, makerAccount, mockTokenAccount); + signerAddress = signerAccount; + relayerAddress = relayerAccount; + orderQuantity = ether(4); + makerTokenAmount = ether(10); + timeToExpiration = 10; + + issuanceOrderParams = await generateFillOrderParameters( + mockSetTokenAccount, + signerAddress, + signerAddress, + mockTokenAccount, + relayerAddress, + orderQuantity, + makerTokenAmount, + timeToExpiration, + ); }); async function subject(): Promise { diff --git a/test/utils/orderWrapper.ts b/test/utils/orderWrapper.ts index 93a7f9a2e..e0f6c9a0c 100644 --- a/test/utils/orderWrapper.ts +++ b/test/utils/orderWrapper.ts @@ -91,6 +91,7 @@ export function hashOrderHex( {value: order.setAddress, type: SolidityTypes.Address}, {value: order.makerAddress, type: SolidityTypes.Address}, {value: order.makerToken, type: SolidityTypes.Address}, + {value: order.relayerAddress, type: SolidityTypes.Address}, {value: order.relayerToken, type: SolidityTypes.Address}, {value: bigNumberToBN(order.quantity), type: SolidityTypes.Uint256}, {value: bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.Uint256}, @@ -122,9 +123,10 @@ export async function generateFillOrderParameters( signerAddress: Address, makerAddress: Address, componentAddress: Address, - quantity: BigNumber = ether(4), - makerTokenAmount: BigNumber = ether(10), - timeToExpiration: number = 10, + relayerAddress: Address, + quantity: BigNumber, + makerTokenAmount: BigNumber, + timeToExpiration: number, ): Promise { const order = { @@ -132,6 +134,7 @@ export async function generateFillOrderParameters( quantity, makerAddress, makerToken: componentAddress, + relayerAddress, makerTokenAmount, expiration: generateTimeStamp(timeToExpiration), relayerToken: componentAddress, @@ -139,7 +142,7 @@ export async function generateFillOrderParameters( salt: generateSalt() } as IssuanceOrder; - const addresses = [order.setAddress, order.makerAddress, order.makerToken, order.relayerToken]; + const addresses = [order.setAddress, order.makerAddress, order.makerToken, order.relayerAddress, order.relayerToken]; const values = [order.quantity, order.makerTokenAmount, order.expiration, order.relayerTokenAmount, order.salt]; const orderHash = hashOrderHex(order); diff --git a/types/common.ts b/types/common.ts index 1941421f3..6e1beada3 100644 --- a/types/common.ts +++ b/types/common.ts @@ -36,6 +36,7 @@ export interface IssuanceOrder { makerToken: Address, makerTokenAmount: BigNumber, expiration: BigNumber, + relayerAddress: Address, relayerToken: Address, relayerTokenAmount: BigNumber, salt: BigNumber