Skip to content
This repository was archived by the owner on Aug 12, 2023. It is now read-only.

Commit e70b687

Browse files
authored
Create jobs for processing Uniswap V2 swap events (#460)
* Introduce fill type concept * Introduce jobs for processing Uniswap V2 swap events * Add a type to all fills
1 parent 93b29cb commit e70b687

File tree

11 files changed

+572
-7
lines changed

11 files changed

+572
-7
lines changed

src/constants.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,19 @@ module.exports = {
5252
PENDING: 0,
5353
SUCCESSFUL: 1,
5454
},
55+
FILL_TYPE: {
56+
REGULAR: 0,
57+
TRANSFORMED_ERC20: 1,
58+
UNISWAP_V2_SWAP: 2,
59+
},
5560
JOB: {
5661
BULK_UPDATE_TOKEN_METADATA: 'bulk-update-token-metadata',
5762
CONVERT_PROTOCOL_FEE: 'convert-protocol-fee',
5863
CONVERT_RELAYER_FEES: 'convert-relayer-fees',
5964
CREATE_TOKEN: 'create-token',
6065
CREATE_TRANSFORMED_ERC20_EVENT_FILLS:
6166
'create-transformed-erc20-event-fills',
67+
CREATE_UNISWAP_V2_SWAP_EVENT_FILL: 'create-uniswap-v2-swap-event-fill',
6268
FETCH_ADDRESS_TYPE: 'fetch-address-type',
6369
FETCH_TOKEN_METADATA: 'fetch-token-metadata',
6470
FETCH_TRANSACTION: 'fetch-transaction',
@@ -71,6 +77,7 @@ module.exports = {
7177
},
7278
QUEUE: {
7379
ADDRESS_PROCESSING: 'address-processing',
80+
EVENT_PROCESSING: 'event-processing',
7481
FILL_INDEXING: 'fill-indexing',
7582
FILL_PROCESSING: 'fill-processing',
7683
INDEXING: 'indexing',

src/consumers/create-transformed-erc20-event-fills/index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ const Bluebird = require('bluebird');
44
const moment = require('moment');
55
const mongoose = require('mongoose');
66

7-
const { JOB, QUEUE, FILL_ACTOR, TOKEN_TYPE } = require('../../constants');
7+
const {
8+
JOB,
9+
QUEUE,
10+
FILL_ACTOR,
11+
FILL_TYPE,
12+
TOKEN_TYPE,
13+
} = require('../../constants');
814
const { publishJob } = require('../../queues');
915
const createFills = require('../../fills/create-fills');
1016
const createNewTokens = require('../../tokens/create-new-tokens');
@@ -161,13 +167,13 @@ const createTransformedERC20EventFills = async (job, { logger }) => {
161167
blockNumber: transaction.blockNumber,
162168
date: transaction.date,
163169
eventId: bridgeEvent._id,
164-
isTransformedERC20: true,
165170
logIndex: bridgeEvent.logIndex,
166171
maker: bridgeEvent.data.from.toLowerCase(),
167172
protocolVersion: bridgeEvent.protocolVersion,
168173
quoteDate: transaction.quoteDate,
169174
taker: transformedERC20Event.data.taker.toLowerCase(),
170175
transactionHash: transaction.hash.toLowerCase(),
176+
type: FILL_TYPE.TRANSFORMED_ERC20,
171177
}));
172178

173179
/*

src/consumers/create-transformed-erc20-event-fills/index.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,6 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
372372
fees: [],
373373
hasValue: false,
374374
immeasurable: false,
375-
isTransformedERC20: true,
376375
logIndex: 191,
377376
maker: '0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48',
378377
protocolVersion: 3,
@@ -382,6 +381,7 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
382381
taker: '0xfe2ecb650fabf37431cba75ec9545284ecfbb03c',
383382
transactionHash:
384383
'0x7444e18b2993978e7757ddf930a765b4839ed197751a3b2b4072df39c02183f4',
384+
type: 1,
385385
},
386386
{
387387
__v: 0,
@@ -419,7 +419,6 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
419419
fees: [],
420420
hasValue: false,
421421
immeasurable: false,
422-
isTransformedERC20: true,
423422
logIndex: 209,
424423
maker: '0xfe01821ca163844203220cd08e4f2b2fb43ae4e4',
425424
protocolVersion: 3,
@@ -429,6 +428,7 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
429428
taker: '0xfe2ecb650fabf37431cba75ec9545284ecfbb03c',
430429
transactionHash:
431430
'0x7444e18b2993978e7757ddf930a765b4839ed197751a3b2b4072df39c02183f4',
431+
type: 1,
432432
},
433433
{
434434
__v: 0,
@@ -466,7 +466,6 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
466466
fees: [],
467467
hasValue: false,
468468
immeasurable: false,
469-
isTransformedERC20: true,
470469
logIndex: 202,
471470
maker: '0x1c29670f7a77f1052d30813a0a4f632c78a02610',
472471
protocolVersion: 3,
@@ -476,6 +475,7 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
476475
taker: '0xfe2ecb650fabf37431cba75ec9545284ecfbb03c',
477476
transactionHash:
478477
'0x7444e18b2993978e7757ddf930a765b4839ed197751a3b2b4072df39c02183f4',
478+
type: 1,
479479
},
480480
]),
481481
);
@@ -641,7 +641,6 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
641641
fees: [],
642642
hasValue: false,
643643
immeasurable: false,
644-
isTransformedERC20: true,
645644
logIndex: 191,
646645
maker: '0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48',
647646
protocolVersion: 3,
@@ -651,6 +650,7 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
651650
taker: '0xfe2ecb650fabf37431cba75ec9545284ecfbb03c',
652651
transactionHash:
653652
'0x7444e18b2993978e7757ddf930a765b4839ed197751a3b2b4072df39c02183f4',
653+
type: 1,
654654
},
655655
{
656656
affiliateAddress: '0x86003b044f70dac0abc80ac8957305b6370893ed',
@@ -683,7 +683,6 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
683683
fees: [],
684684
hasValue: false,
685685
immeasurable: false,
686-
isTransformedERC20: true,
687686
logIndex: 209,
688687
maker: '0xfe01821ca163844203220cd08e4f2b2fb43ae4e4',
689688
protocolVersion: 3,
@@ -693,6 +692,7 @@ describe('consumers/create-transformed-erc20-event-fills', () => {
693692
taker: '0xfe2ecb650fabf37431cba75ec9545284ecfbb03c',
694693
transactionHash:
695694
'0x7444e18b2993978e7757ddf930a765b4839ed197751a3b2b4072df39c02183f4',
695+
type: 1,
696696
},
697697
]);
698698

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
const { BigNumber } = require('@0x/utils');
2+
const moment = require('moment');
3+
const mongoose = require('mongoose');
4+
5+
const {
6+
JOB,
7+
QUEUE,
8+
FILL_ACTOR,
9+
FILL_TYPE,
10+
TOKEN_TYPE,
11+
} = require('../../constants');
12+
const { publishJob } = require('../../queues');
13+
const createFills = require('../../fills/create-fills');
14+
const createNewTokens = require('../../tokens/create-new-tokens');
15+
const Event = require('../../model/event');
16+
const Fill = require('../../model/fill');
17+
const getTransactionByHash = require('../../transactions/get-transaction-by-hash');
18+
const withTransaction = require('../../util/with-transaction');
19+
20+
const createUniswapV2SwapEventFill = async (job, { logger }) => {
21+
const { eventId } = job.data;
22+
23+
/*
24+
* Ensure the specified eventId is valid and that the associated event exists.
25+
*/
26+
if (!mongoose.Types.ObjectId.isValid(eventId)) {
27+
throw new Error(`Invalid eventId: ${eventId}`);
28+
}
29+
30+
const event = await Event.findById(eventId);
31+
32+
if (event === null) {
33+
throw new Error(`Cannot find event: ${eventId}`);
34+
}
35+
36+
const existingFill = await Fill.findById(eventId);
37+
38+
if (existingFill !== null) {
39+
logger.warn(`fill already created for event: ${eventId}`);
40+
return;
41+
}
42+
43+
/**
44+
* Verify that the associated transaction has been fetched.
45+
*/
46+
const transaction = await getTransactionByHash(event.transactionHash);
47+
48+
if (transaction === null) {
49+
/*
50+
* If more than 5 minutes have passed since the UniswapV2Swap event was fetched then
51+
* this might indicate a bottleneck or failure in the transaction fetching job.
52+
*/
53+
if (moment().diff(event.dateIngested, 'minutes') >= 5) {
54+
logger.warn(`transaction not found for event: ${event._id}`);
55+
}
56+
57+
await publishJob(
58+
QUEUE.EVENT_PROCESSING,
59+
JOB.CREATE_UNISWAP_V2_SWAP_EVENT_FILL,
60+
job.data,
61+
{ delay: 30000 },
62+
);
63+
64+
return;
65+
}
66+
67+
/*
68+
* Finally, once all checks have passed, create the fill and associate token documents.
69+
*/
70+
const fill = {
71+
_id: event._id,
72+
affiliateAddress:
73+
transaction.affiliateAddress !== undefined
74+
? transaction.affiliateAddress.toLowerCase()
75+
: undefined,
76+
assets: [
77+
{
78+
actor: FILL_ACTOR.MAKER,
79+
amount: new BigNumber(event.data.makerAmount).toNumber(),
80+
tokenAddress: event.data.makerToken,
81+
82+
/*
83+
Uniswap V2 Bridge – this is a bit of a hack for tracking purposes and should
84+
be replaced longer-term with something better (e.g. liquidity source)
85+
*/
86+
bridgeAddress: '0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48',
87+
},
88+
{
89+
actor: FILL_ACTOR.TAKER,
90+
amount: new BigNumber(event.data.takerAmount).toNumber(),
91+
tokenAddress: event.data.takerToken.toLowerCase(),
92+
},
93+
],
94+
blockHash: transaction.blockHash.toLowerCase(),
95+
blockNumber: transaction.blockNumber,
96+
date: transaction.date,
97+
eventId: event._id,
98+
logIndex: event.logIndex,
99+
maker: event.data.maker.toLowerCase(),
100+
protocolVersion: event.protocolVersion,
101+
quoteDate: transaction.quoteDate,
102+
taker: event.data.taker.toLowerCase(),
103+
transactionHash: transaction.hash.toLowerCase(),
104+
type: FILL_TYPE.UNISWAP_V2_SWAP,
105+
};
106+
107+
await createNewTokens(
108+
fill.assets.map(asset => ({
109+
address: asset.tokenAddress,
110+
type: TOKEN_TYPE.ERC20,
111+
})),
112+
);
113+
114+
await withTransaction(async session => {
115+
await createFills([fill], { session });
116+
});
117+
118+
logger.info(`created fill for UniswapV2Swap event: ${eventId}`);
119+
};
120+
121+
module.exports = {
122+
fn: createUniswapV2SwapEventFill,
123+
jobName: JOB.CREATE_UNISWAP_V2_SWAP_EVENT_FILL,
124+
queueName: QUEUE.EVENT_PROCESSING,
125+
};

0 commit comments

Comments
 (0)