Skip to content
Open
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
266 changes: 266 additions & 0 deletions src.ts/_tests/test-providers-format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
import assert from "assert";

import { formatLog, formatReceiptLog } from "../providers/format.js";
import { Log } from "../providers/provider.js";

describe("Test Log Formatting", function() {
describe("formatLog with blockTimestamp", function() {
it("should parse blockTimestamp from hex string", function() {
const logData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
blockTimestamp: '0x65a1b2c3',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatLog(logData);

assert.strictEqual(formatted.blockTimestamp, 1705095875, "blockTimestamp should be parsed to number");
assert.strictEqual(formatted.blockNumber, 16, "blockNumber should be parsed");
assert.strictEqual(formatted.transactionIndex, 1, "transactionIndex should be parsed");
});

it("should handle missing blockTimestamp gracefully", function() {
const logData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatLog(logData);

assert.strictEqual(formatted.blockTimestamp, undefined, "blockTimestamp should be undefined when not provided");
assert.strictEqual(formatted.blockNumber, 16, "blockNumber should still be parsed");
});

it("should handle null blockTimestamp", function() {
const logData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
blockTimestamp: null,
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatLog(logData);

assert.strictEqual(formatted.blockTimestamp, undefined, "blockTimestamp should be undefined when null");
});

it("should parse blockTimestamp 0x0", function() {
const logData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
blockTimestamp: '0x0',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatLog(logData);

assert.strictEqual(formatted.blockTimestamp, 0, "blockTimestamp should be 0 for 0x0");
});
});

describe("formatReceiptLog with blockTimestamp", function() {
it("should parse blockTimestamp from hex string", function() {
const logData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
blockTimestamp: '0x65a1b2c3',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatReceiptLog(logData);

assert.strictEqual(formatted.blockTimestamp, 1705095875, "blockTimestamp should be parsed to number");
assert.strictEqual(formatted.blockNumber, 16, "blockNumber should be parsed");
assert.strictEqual(formatted.transactionIndex, 1, "transactionIndex should be parsed");
});

it("should handle missing blockTimestamp gracefully", function() {
const logData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatReceiptLog(logData);

assert.strictEqual(formatted.blockTimestamp, undefined, "blockTimestamp should be undefined when not provided");
});
});

describe("Log class with blockTimestamp", function() {
const mockProvider: any = {
getBlock: () => Promise.resolve(null),
getTransaction: () => Promise.resolve(null),
getTransactionReceipt: () => Promise.resolve(null)
};

it("should store blockTimestamp in Log instance", function() {
const logParams = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: 16,
blockTimestamp: 1705095875,
data: '0xabcd',
index: 5,
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: 1
};

const log = new Log(logParams, mockProvider);

assert.strictEqual(log.blockTimestamp, 1705095875, "Log instance should have blockTimestamp");
assert.strictEqual(log.blockNumber, 16, "Log instance should have blockNumber");
assert.strictEqual(log.address, '0x1234567890123456789012345678901234567890', "Log instance should have address");
});

it("should handle undefined blockTimestamp in Log instance", function() {
const logParams = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: 16,
data: '0xabcd',
index: 5,
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: 1
};

const log = new Log(logParams, mockProvider);

assert.strictEqual(log.blockTimestamp, undefined, "Log instance should have undefined blockTimestamp");
});

it("should include blockTimestamp in toJSON output", function() {
const logParams = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: 16,
blockTimestamp: 1705095875,
data: '0xabcd',
index: 5,
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: 1
};

const log = new Log(logParams, mockProvider);
const json = log.toJSON();

assert.strictEqual(json._type, "log", "JSON should have _type");
assert.strictEqual(json.blockTimestamp, 1705095875, "JSON should include blockTimestamp");
assert.strictEqual(json.blockNumber, 16, "JSON should include blockNumber");
assert.strictEqual(json.address, '0x1234567890123456789012345678901234567890', "JSON should include address");
});

it("should exclude undefined blockTimestamp from toJSON output", function() {
const logParams = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: 16,
data: '0xabcd',
index: 5,
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: 1
};

const log = new Log(logParams, mockProvider);
const json = log.toJSON();

assert.strictEqual(json._type, "log", "JSON should have _type");
assert.ok(!("blockTimestamp" in json), "blockTimestamp key should not be present in JSON when undefined");
});
});

describe("Integration: formatLog -> Log class", function() {
const mockProvider: any = {
getBlock: () => Promise.resolve(null),
getTransaction: () => Promise.resolve(null),
getTransactionReceipt: () => Promise.resolve(null)
};

it("should preserve blockTimestamp through formatting and Log creation", function() {
const rawLogData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
blockTimestamp: '0x65a1b2c3',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatLog(rawLogData);
const log = new Log(formatted, mockProvider);

assert.strictEqual(log.blockTimestamp, 1705095875, "blockTimestamp should be preserved through formatting and Log creation");
assert.strictEqual(log.toJSON().blockTimestamp, 1705095875, "blockTimestamp should be in JSON output");
});

it("should handle missing blockTimestamp through full pipeline", function() {
const rawLogData = {
address: '0x1234567890123456789012345678901234567890',
blockHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
blockNumber: '0x10',
data: '0xabcd',
logIndex: '0x5',
removed: false,
topics: ['0x2222222222222222222222222222222222222222222222222222222222222222'],
transactionHash: '0x3333333333333333333333333333333333333333333333333333333333333333',
transactionIndex: '0x1'
};

const formatted = formatLog(rawLogData);
const log = new Log(formatted, mockProvider);

assert.strictEqual(log.blockTimestamp, undefined, "blockTimestamp should be undefined through full pipeline");
assert.strictEqual(log.blockNumber, 16, "blockNumber should still work");
});
});
});
2 changes: 1 addition & 1 deletion src.ts/_tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fs from "fs"
import path from "path";
import zlib from "zlib";

export const FAUCET_PRIVATEKEY = process.env.FAUCET_PRIVATEKEY || "MISSING_GITHUB_SECRET";
export const FAUCET_PRIVATEKEY = process.env.FAUCET_PRIVATEKEY || "";

export const INFURA_APIKEY = process.env.INFURA_APIKEY || "";

Expand Down
2 changes: 2 additions & 0 deletions src.ts/providers/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const _formatLog = object({
address: getAddress,
blockHash: formatHash,
blockNumber: getNumber,
blockTimestamp: allowNull(getNumber, undefined),
data: formatData,
index: getNumber,
removed: allowNull(formatBoolean, false),
Expand Down Expand Up @@ -150,6 +151,7 @@ export function formatBlock(value: any): BlockParams {
const _formatReceiptLog = object({
transactionIndex: getNumber,
blockNumber: getNumber,
blockTimestamp: allowNull(getNumber, undefined),
transactionHash: formatHash,
address: getAddress,
topics: arrayOf(formatHash),
Expand Down
8 changes: 6 additions & 2 deletions src.ts/providers/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ export interface LogParams {
*/
blockNumber: number;

/**
* The timestamp of the block that included the transaction for this
* log.
*/
blockTimestamp?: number;

/**
* Whether this log was removed due to the transaction it was included
* in being removed dur to an orphaned block.
Expand Down Expand Up @@ -414,5 +420,3 @@ export interface TransactionResponseParams {
*/
authorizationList: null | Array<Authorization>;
};


15 changes: 14 additions & 1 deletion src.ts/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,12 @@ export class Log implements LogParams {
*/
readonly blockNumber!: number;

/**
* The timestamp of the block that included the transaction for this
* log.
*/
readonly blockTimestamp?: number;

/**
* If the **Log** represents a block that was removed due to an orphaned
* block, this will be true.
Expand Down Expand Up @@ -878,6 +884,7 @@ export class Log implements LogParams {
transactionHash: log.transactionHash,
blockHash: log.blockHash,
blockNumber: log.blockNumber,
blockTimestamp: log.blockTimestamp,

removed: log.removed,

Expand All @@ -900,11 +907,17 @@ export class Log implements LogParams {
removed, topics, transactionHash, transactionIndex
} = this;

return {
const result: any = {
_type: "log",
address, blockHash, blockNumber, data, index,
removed, topics, transactionHash, transactionIndex
};

if (this.blockTimestamp != null) {
result.blockTimestamp = this.blockTimestamp;
}

return result;
}

/**
Expand Down