Add transactionHash to OrderState and emit it from OrderWatcher subscription

This commit is contained in:
Fabio Berger 2018-09-25 16:10:13 +01:00
parent 7570f3db51
commit 9eecf3683b
5 changed files with 64 additions and 13 deletions

View File

@ -114,7 +114,7 @@ export class OrderStateUtils {
* @return State relevant to the signedOrder, as well as whether the signedOrder is "valid". * @return State relevant to the signedOrder, as well as whether the signedOrder is "valid".
* Validity is defined as a non-zero amount of the order can still be filled. * Validity is defined as a non-zero amount of the order can still be filled.
*/ */
public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> { public async getOpenOrderStateAsync(signedOrder: SignedOrder, transactionHash?: string): Promise<OrderState> {
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder); const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash); const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
@ -134,6 +134,7 @@ export class OrderStateUtils {
isValid: true, isValid: true,
orderHash, orderHash,
orderRelevantState, orderRelevantState,
transactionHash,
}; };
return orderState; return orderState;
} else { } else {
@ -141,6 +142,7 @@ export class OrderStateUtils {
isValid: false, isValid: false,
orderHash, orderHash,
error: orderValidationResult.error, error: orderValidationResult.error,
transactionHash,
}; };
return orderState; return orderState;
} }

View File

@ -120,5 +120,25 @@ describe('OrderStateUtils', () => {
const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder);
expect(orderState.isValid).to.eq(false); expect(orderState.isValid).to.eq(false);
}); });
it('should include the transactionHash in orderState if supplied in method invocation', async () => {
const makerAssetAmount = new BigNumber(10);
const takerAssetAmount = new BigNumber(10000000000000000);
const takerBalance = takerAssetAmount;
const orderFilledAmount = new BigNumber(0);
const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance);
const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount);
const [signedOrder] = testOrderFactory.generateTestSignedOrders(
{
makerAssetAmount,
takerAssetAmount,
},
1,
);
const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher);
const transactionHash = '0xdeadbeef';
const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash);
expect(orderState.transactionHash).to.eq(transactionHash);
});
}); });
}); });

View File

@ -275,6 +275,7 @@ export class OrderWatcher {
return; // noop return; // noop
} }
const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>; const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>;
const transactionHash = decodedLog.transactionHash;
switch (decodedLog.event) { switch (decodedLog.event) {
case ERC20TokenEvents.Approval: case ERC20TokenEvents.Approval:
case ERC721TokenEvents.Approval: { case ERC721TokenEvents.Approval: {
@ -290,7 +291,7 @@ export class OrderWatcher {
args._owner, args._owner,
tokenAssetData, tokenAssetData,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} else { } else {
// ERC721 // ERC721
@ -303,7 +304,7 @@ export class OrderWatcher {
args._owner, args._owner,
tokenAssetData, tokenAssetData,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} }
} }
@ -322,7 +323,7 @@ export class OrderWatcher {
args._from, args._from,
tokenAssetData, tokenAssetData,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} else { } else {
// ERC721 // ERC721
@ -336,7 +337,7 @@ export class OrderWatcher {
args._from, args._from,
tokenAssetData, tokenAssetData,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} }
} }
@ -350,7 +351,7 @@ export class OrderWatcher {
args._owner, args._owner,
tokenAddress, tokenAddress,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} }
case WETH9Events.Deposit: { case WETH9Events.Deposit: {
@ -363,7 +364,7 @@ export class OrderWatcher {
args._owner, args._owner,
tokenAssetData, tokenAssetData,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} }
case WETH9Events.Withdrawal: { case WETH9Events.Withdrawal: {
@ -376,7 +377,7 @@ export class OrderWatcher {
args._owner, args._owner,
tokenAssetData, tokenAssetData,
); );
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} }
case ExchangeEvents.Fill: { case ExchangeEvents.Fill: {
@ -387,7 +388,7 @@ export class OrderWatcher {
const orderHash = args.orderHash; const orderHash = args.orderHash;
const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]); const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
if (isOrderWatched) { if (isOrderWatched) {
await this._emitRevalidateOrdersAsync([orderHash]); await this._emitRevalidateOrdersAsync([orderHash], transactionHash);
} }
break; break;
} }
@ -399,7 +400,7 @@ export class OrderWatcher {
const orderHash = args.orderHash; const orderHash = args.orderHash;
const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]); const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
if (isOrderWatched) { if (isOrderWatched) {
await this._emitRevalidateOrdersAsync([orderHash]); await this._emitRevalidateOrdersAsync([orderHash], transactionHash);
} }
break; break;
} }
@ -410,7 +411,7 @@ export class OrderWatcher {
this._orderFilledCancelledLazyStore.deleteAllIsCancelled(); this._orderFilledCancelledLazyStore.deleteAllIsCancelled();
// Revalidate orders // Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByMaker(args.makerAddress); const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByMaker(args.makerAddress);
await this._emitRevalidateOrdersAsync(orderHashes); await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
break; break;
} }
@ -418,12 +419,12 @@ export class OrderWatcher {
throw errorUtils.spawnSwitchErr('decodedLog.event', decodedLog.event); throw errorUtils.spawnSwitchErr('decodedLog.event', decodedLog.event);
} }
} }
private async _emitRevalidateOrdersAsync(orderHashes: string[]): Promise<void> { private async _emitRevalidateOrdersAsync(orderHashes: string[], transactionHash?: string): Promise<void> {
for (const orderHash of orderHashes) { for (const orderHash of orderHashes) {
const signedOrder = this._orderByOrderHash[orderHash]; const signedOrder = this._orderByOrderHash[orderHash];
// Most of these calls will never reach the network because the data is fetched from stores // Most of these calls will never reach the network because the data is fetched from stores
// and only updated when cache is invalidated // and only updated when cache is invalidated
const orderState = await this._orderStateUtils.getOpenOrderStateAsync(signedOrder); const orderState = await this._orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash);
if (_.isUndefined(this._callbackIfExists)) { if (_.isUndefined(this._callbackIfExists)) {
break; // Unsubscribe was called break; // Unsubscribe was called
} }

View File

@ -250,6 +250,32 @@ describe('OrderWatcher', () => {
await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress); await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress);
})().catch(done); })().catch(done);
}); });
it('should include transactionHash in emitted orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerAssetData,
takerAssetData,
makerAddress,
takerAddress,
fillableAmount,
);
await orderWatcher.addOrderAsync(signedOrder);
let transactionHash: string;
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
expect(orderState.isValid).to.be.false();
const invalidOrderState = orderState as OrderStateInvalid;
expect(invalidOrderState.transactionHash).to.be.equal(transactionHash);
});
orderWatcher.subscribe(callback);
transactionHash = await contractWrappers.exchange.fillOrderAsync(
signedOrder,
fillableAmount,
takerAddress,
);
})().catch(done);
});
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => { it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
(async () => { (async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync( signedOrder = await fillScenarios.createFillableSignedOrderAsync(

View File

@ -111,12 +111,14 @@ export interface OrderStateValid {
isValid: true; isValid: true;
orderHash: string; orderHash: string;
orderRelevantState: OrderRelevantState; orderRelevantState: OrderRelevantState;
transactionHash?: string;
} }
export interface OrderStateInvalid { export interface OrderStateInvalid {
isValid: false; isValid: false;
orderHash: string; orderHash: string;
error: ExchangeContractErrs; error: ExchangeContractErrs;
transactionHash?: string;
} }
export type OrderState = OrderStateValid | OrderStateInvalid; export type OrderState = OrderStateValid | OrderStateInvalid;