Skip to content

Commit f1c5fe7

Browse files
authored
feat: add optional expression logging to GRE (#728)
* feat: add optional expression logging to GRE Closes: #702 Signed-off-by: Tomás Migone <[email protected]>
1 parent fdc0bae commit f1c5fe7

File tree

4 files changed

+101
-3
lines changed

4 files changed

+101
-3
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ bin/
1919
# Coverage and other reports
2020
/reports
2121
coverage.json
22+
23+
tx-*.log

cli/contracts.ts

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import { providers, Signer } from 'ethers'
1+
import {
2+
Contract,
3+
ContractFunction,
4+
ContractReceipt,
5+
ContractTransaction,
6+
providers,
7+
Signer,
8+
} from 'ethers'
9+
import { Provider } from '@ethersproject/providers'
10+
import lodash from 'lodash'
11+
import fs from 'fs'
212

313
import { AddressBook } from './address-book'
414
import { logger } from './logging'
@@ -45,12 +55,17 @@ export interface NetworkContracts {
4555
export const loadContracts = (
4656
addressBook: AddressBook,
4757
signerOrProvider?: Signer | providers.Provider,
58+
enableTXLogging = false,
4859
): NetworkContracts => {
4960
const contracts = {}
5061
for (const contractName of addressBook.listEntries()) {
5162
const contractEntry = addressBook.getEntry(contractName)
5263
try {
53-
const contract = getContractAt(contractName, contractEntry.address)
64+
let contract = getContractAt(contractName, contractEntry.address)
65+
if (enableTXLogging) {
66+
contract.connect = getWrappedConnect(contract, contractName)
67+
contract = wrapCalls(contract, contractName)
68+
}
5469
contracts[contractName] = contract
5570
if (signerOrProvider) {
5671
contracts[contractName] = contracts[contractName].connect(signerOrProvider)
@@ -61,3 +76,77 @@ export const loadContracts = (
6176
}
6277
return contracts as NetworkContracts
6378
}
79+
80+
// Returns a contract connect function that wrapps contract calls with wrapCalls
81+
function getWrappedConnect(
82+
contract: Contract,
83+
contractName: string,
84+
): (signerOrProvider: string | Provider | Signer) => Contract {
85+
const call = contract.connect.bind(contract)
86+
const override = (signerOrProvider: string | Provider | Signer): Contract => {
87+
const connectedContract = call(signerOrProvider)
88+
connectedContract.connect = getWrappedConnect(connectedContract, contractName)
89+
return wrapCalls(connectedContract, contractName)
90+
}
91+
return override
92+
}
93+
94+
// Returns a contract with wrapped calls
95+
// The wrapper will run the tx, wait for confirmation and log the details
96+
function wrapCalls(contract: Contract, contractName: string): Contract {
97+
const wrappedContract = lodash.cloneDeep(contract)
98+
99+
for (const fn of Object.keys(contract.functions)) {
100+
const call: ContractFunction<ContractTransaction> = contract.functions[fn]
101+
const override = async (...args: Array<any>): Promise<ContractTransaction> => {
102+
// Make the call
103+
const tx = await call(...args)
104+
logContractCall(tx, contractName, fn, args)
105+
106+
// Wait for confirmation
107+
const receipt = await contract.provider.waitForTransaction(tx.hash)
108+
logContractReceipt(tx, receipt)
109+
return tx
110+
}
111+
112+
wrappedContract.functions[fn] = override
113+
wrappedContract[fn] = override
114+
}
115+
116+
return wrappedContract
117+
}
118+
119+
function logContractCall(
120+
tx: ContractTransaction,
121+
contractName: string,
122+
fn: string,
123+
args: Array<any>,
124+
) {
125+
const msg = []
126+
msg.push(`> Sent transaction ${contractName}.${fn}`)
127+
msg.push(` sender: ${tx.from}`)
128+
msg.push(` contract: ${tx.to}`)
129+
msg.push(` params: [ ${args} ]`)
130+
msg.push(` txHash: ${tx.hash}`)
131+
132+
logToConsoleAndFile(msg)
133+
}
134+
135+
function logContractReceipt(tx: ContractTransaction, receipt: ContractReceipt) {
136+
const msg = []
137+
msg.push(
138+
receipt.status ? `✔ Transaction succeeded: ${tx.hash}` : `✖ Transaction failed: ${tx.hash}`,
139+
)
140+
141+
logToConsoleAndFile(msg)
142+
}
143+
144+
function logToConsoleAndFile(msg: string[]) {
145+
const isoDate = new Date().toISOString()
146+
const fileName = `tx-${isoDate.substring(0, 10)}.log`
147+
148+
msg.map((line) => {
149+
console.log(line)
150+
fs.appendFileSync(fileName, `[${isoDate}] ${line}\n`)
151+
})
152+
}

gre/gre.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => {
4343
logDebug('*** Initializing Graph Runtime Environment (GRE) ***')
4444
logDebug(`Main network: ${hre.network.name}`)
4545

46+
const enableTxLogging = opts.enableTxLogging ?? false
47+
logDebug(`Tx logging: ${enableTxLogging ? 'enabled' : 'disabled'}`)
48+
4649
const { l1ChainId, l2ChainId, isHHL1 } = getChains(hre.network.config.chainId)
4750
const { l1Provider, l2Provider } = getProviders(hre, l1ChainId, l2ChainId, isHHL1)
4851
const addressBookPath = getAddressBookPath(hre, opts)
@@ -69,6 +72,7 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => {
6972
l1GraphConfigPath,
7073
addressBookPath,
7174
isHHL1,
75+
enableTxLogging,
7276
l1GetWallets,
7377
l1GetWallet,
7478
)
@@ -79,6 +83,7 @@ extendEnvironment((hre: HardhatRuntimeEnvironment) => {
7983
l2GraphConfigPath,
8084
addressBookPath,
8185
isHHL1,
86+
enableTxLogging,
8287
l2GetWallets,
8388
l2GetWallet,
8489
)
@@ -102,6 +107,7 @@ function buildGraphNetworkEnvironment(
102107
graphConfigPath: string | undefined,
103108
addressBookPath: string,
104109
isHHL1: boolean,
110+
enableTxLogging: boolean,
105111
getWallets: () => Promise<Wallet[]>,
106112
getWallet: (address: string) => Promise<Wallet>,
107113
): GraphNetworkEnvironment | null {
@@ -127,7 +133,7 @@ function buildGraphNetworkEnvironment(
127133
addressBook: lazyObject(() => getAddressBook(addressBookPath, chainId.toString())),
128134
graphConfig: lazyObject(() => readConfig(graphConfigPath, true)),
129135
contracts: lazyObject(() =>
130-
loadContracts(getAddressBook(addressBookPath, chainId.toString()), provider),
136+
loadContracts(getAddressBook(addressBookPath, chainId.toString()), provider, enableTxLogging),
131137
),
132138
getDeployer: lazyFunction(() => () => getDeployer(provider)),
133139
getNamedAccounts: lazyFunction(() => () => getNamedAccounts(provider, graphConfigPath)),

gre/type-extensions.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export interface GraphRuntimeEnvironmentOptions {
1010
l1GraphConfig?: string
1111
l2GraphConfig?: string
1212
graphConfig?: string
13+
enableTxLogging?: boolean
1314
}
1415

1516
export type AccountNames =

0 commit comments

Comments
 (0)