Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

feat: added a unique identifier to the quote within the timestamp metadata … #281

Merged
merged 3 commits into from
Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const ONE_SECOND_MS = 1000;
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
export const TEN_MINUTES_MS = ONE_MINUTE_MS * 10;
export const DEFAULT_VALIDATION_GAS_LIMIT = 10e6;
export const HEX_BASE = 16;

// The number of orders to post to Mesh at one time
export const MESH_ORDERS_BATCH_SIZE = 200;
Expand Down
19 changes: 19 additions & 0 deletions src/utils/number_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const numberUtils = {
// from MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
randomNumberInclusive: (minimumSpecified: number, maximumSpecified: number): number => {
const min = Math.ceil(minimumSpecified);
const max = Math.floor(maximumSpecified);
return Math.floor(Math.random() * (max - min + 1)) + min; // The maximum is inclusive and the minimum is inclusive
},
// creates a random hex number of desired length by stringing together
// random integers from 1-15, guaranteeing the
// result is a hex number of the given length
randomHexNumberOfLength: (numberLength: number): string => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice function!

let res = '';
for (let i = 0; i < numberLength; i++) {
// tslint:disable-next-line:custom-no-magic-numbers
res = `${res}${numberUtils.randomNumberInclusive(1, 15).toString(16)}`;
}
return res;
},
};
19 changes: 17 additions & 2 deletions src/utils/service_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
GAS_BURN_REFUND,
GST_DIVISOR,
GST_INTERACTION_COST,
HEX_BASE,
ONE_SECOND_MS,
PERCENTAGE_SIG_DIGITS,
SSTORE_COST,
Expand All @@ -29,6 +30,8 @@ import { GasTokenRefundInfo, GetSwapQuoteResponseLiquiditySource } from '../type
import { orderUtils } from '../utils/order_utils';
import { findTokenDecimalsIfExists } from '../utils/token_metadata_utils';

import { numberUtils } from './number_utils';

export const serviceUtils = {
attributeSwapQuoteOrders(
swapQuote: MarketSellSwapQuote | MarketBuySwapQuote,
Expand Down Expand Up @@ -69,8 +72,20 @@ export const serviceUtils = {
stateMutability: 'view',
type: 'function',
});
const timestamp = new BigNumber(Date.now() / ONE_SECOND_MS).integerValue();
const encodedAffiliateData = affiliateCallDataEncoder.encode([affiliateAddressOrDefault, timestamp]);

// Generate unique identiifer
const timestampInSeconds = new BigNumber(Date.now() / ONE_SECOND_MS).integerValue();
const hexTimestamp = timestampInSeconds.toString(HEX_BASE);
const randomNumber = numberUtils.randomHexNumberOfLength(10);

// Concatenate the hex identifier with the hex timestamp
// In the final encoded call data, this will leave us with a 5-byte ID followed by
// a 4-byte timestamp, and won't break parsers of the timestamp made prior to the
// addition of the ID
const uniqueIdentifier = new BigNumber(`${randomNumber}${hexTimestamp}`, HEX_BASE);

// Encode additional call data and return
const encodedAffiliateData = affiliateCallDataEncoder.encode([affiliateAddressOrDefault, uniqueIdentifier]);
const affiliatedData = `${data}${encodedAffiliateData.slice(2)}`;
return affiliatedData;
},
Expand Down
1 change: 1 addition & 0 deletions test/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export const SYMBOL_TO_ADDRESS: ObjectMap<string> = {
ZRX: ZRX_TOKEN_ADDRESS,
WETH: WETH_TOKEN_ADDRESS,
};
export const AFFILIATE_DATA_SELECTOR = '869584cd';
24 changes: 23 additions & 1 deletion test/service_utils_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'mocha';
import { ZERO } from '../src/constants';
import { serviceUtils } from '../src/utils/service_utils';

import { MAX_INT } from './constants';
import { AFFILIATE_DATA_SELECTOR, MAX_INT } from './constants';

const SUITE_NAME = 'serviceUtils test';

Expand Down Expand Up @@ -68,4 +68,26 @@ describe(SUITE_NAME, () => {
expect(gasTokenGasCost.toNumber()).to.be.eq(0);
});
});
describe('attributeCallData', () => {
it('it returns a reasonable ID and timestamp', () => {
const fakeCallData = '0x0000000000000';
const fakeAffiliate = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
const attributedCallData = serviceUtils.attributeCallData(fakeCallData, fakeAffiliate);
const currentTime = new Date();

// parse out items from call data to ensure they are reasonable values
const selectorPos = attributedCallData.indexOf(AFFILIATE_DATA_SELECTOR);
const affiliateAddress = '0x'.concat(attributedCallData.substring(selectorPos + 32, selectorPos + 72));
const randomId = attributedCallData.substring(selectorPos + 118, selectorPos + 128);
const timestampFromCallDataHex = attributedCallData.substring(selectorPos + 128, selectorPos + 136);
const timestampFromCallData = parseInt(timestampFromCallDataHex, 16);

expect(affiliateAddress).to.be.eq(fakeAffiliate);
// call data timestamp is within 3 seconds of timestamp created during test
expect(timestampFromCallData).to.be.greaterThan(currentTime.getTime() / 1000 - 3);
expect(timestampFromCallData).to.be.lessThan(currentTime.getTime() / 1000 + 3);
// ID is a 10-digit hex number
expect(randomId).to.match(/[0-9A-Fa-f]{10}/);
});
});
});