@ethersproject/abstract-provider#Log TypeScript Examples

The following examples show how to use @ethersproject/abstract-provider#Log. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
getTXReceiptByHash = async (txHash: string): Promise<TXReceipt | null> => {
    const tx = await this._getMinedTXReceipt(txHash);
    if (!tx) return null;

    return this.formatter.receipt({
      to: tx.to || null,
      from: tx.from,
      contractAddress: tx.contractAddress || null,
      transactionIndex: tx.transactionIndex,
      gasUsed: tx.gasUsed,
      logsBloom: tx.logsBloom,
      blockHash: tx.blockHash,
      transactionHash: tx.transactionHash,
      logs: Array.isArray(tx.logs) ? tx.logs : (tx.logs.nodes as Log[]),
      blockNumber: tx.blockNumber,
      cumulativeGasUsed: tx.cumulativeGasUsed,
      type: tx.type,
      status: tx.status,
      effectiveGasPrice: EFFECTIVE_GAS_PRICE,
      confirmations: (await this._getBlockHeader('latest')).number.toNumber() - tx.blockNumber
    });
  };
Example #2
Source File: Provider.ts    From evm-provider.js with Apache License 2.0 6 votes vote down vote up
/**
   * Get an array of filtered logs from the chain's head.
   * @param filter The filter to apply to the logs
   * @returns A promise that resolves to an array of filtered logs
   */
  async getLogs(filter: Filter): Promise<Array<Log>> {
    if (!this.dataProvider) return this._fail('getLogs');
    return this.dataProvider.getLogs(filter, this._resolveBlockNumber);
  }
Example #3
Source File: DataProvider.ts    From evm-provider.js with Apache License 2.0 6 votes vote down vote up
/**
   *
   * @param filter The filter to apply to the logs
   * @param resolveBlockNumber The block to retrieve the logs from, defaults
   * to the head
   * @returns A promise that resolves to an array of filtered logs
   */
  abstract getLogs(
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    filter: any,
    resolveBlockNumber: (
      blockTag?: BlockTag | Promise<BlockTag>
    ) => Promise<number | undefined>
  ): Promise<Array<Log>>;
Example #4
Source File: transaction.ts    From tx2uml with MIT License 6 votes vote down vote up
static parseTransactionLogs(logs: Array<Log>, contracts: Contracts) {
        // for each tx log
        for (const log of logs) {
            // see if we have the contract source for the log
            const contract = contracts[log.address.toLowerCase()]
            if (contract?.ethersContract) {
                // try and parse the log topic
                try {
                    const event =
                        contract.ethersContract.interface.parseLog(log)
                    contract.events.push(parseEvent(contract, event))
                } catch (err) {
                    debug(
                        `Failed to parse log with topic ${log?.topics[0]} on contract ${log.address}`
                    )
                }
            }
            // also parse the events on any contracts that are delegated to
            contract?.delegatedToContracts?.forEach(delegatedToContract => {
                // try and parse the log topic
                try {
                    const event =
                        delegatedToContract.ethersContract.interface.parseLog(
                            log
                        )
                    contract.events.push(parseEvent(contract, event))
                } catch (err) {
                    debug(
                        `Failed to parse log with topic ${log?.topics[0]} on contract ${log.address}`
                    )
                }
            })
        }
    }
Example #5
Source File: EthereumNodeClient.ts    From tx2uml with MIT License 6 votes vote down vote up
// Parse Transfer events from a transaction receipt
    static parseTransferEvents(logs: Array<Log>): Transfer[] {
        const transferEvents: Transfer[] = []
        // parse eve
        const tokenEventInterface = new ethers.utils.Interface(
            TransferEventsABI
        )
        logs.forEach(log => {
            try {
                const event = tokenEventInterface.parseLog(log)
                if (event.name === "Transfer") {
                    transferEvents.push({
                        to: event.args.to,
                        from: event.args.from,
                        value: event.args.value,
                        tokenAddress: log.address,
                        ether: false,
                    })
                }
            } catch (err) {
                if (err.reason !== "no matching event")
                    throw new VError(err, "Failed to parse event log")
            }
        })

        return transferEvents
    }
Example #6
Source File: useRawLogs.ts    From useDApp with MIT License 6 votes vote down vote up
/**
 * @public
 */
export function useRawLogs(
  filter: Filter | FilterByBlockHash | Promise<Filter | FilterByBlockHash> | Falsy,
  queryParams: QueryParams = {}
): Log[] | undefined {
  const { library } = useEthers()
  const providers = useReadonlyNetworks()
  const _blockNumber = useBlockNumber()
  const blockNumbers = useBlockNumbers()

  const [logs, setLogs] = useState<Log[] | undefined>()

  const { chainId } = queryParams

  const [provider, blockNumber] = useMemo(
    () => (chainId ? [providers[chainId], blockNumbers[chainId]] : [library, _blockNumber]),
    [providers, library, blockNumbers, _blockNumber, chainId]
  )

  async function updateLogs() {
    setLogs(!filter ? undefined : await provider?.getLogs(filter))
  }

  useEffect(() => {
    void updateLogs()
  }, [provider, blockNumber])

  return logs
}
Example #7
Source File: eip1193-bridge.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
// async eth_newFilter(params: any[]): Promise<any> {

  // }

  // async eth_newBlockFilter(params: any[]): Promise<any> {

  // }

  // async eth_newPendingTransactionFilter(params: any[]): Promise<any> {

  // }

  // async eth_uninstallFilter(params: any[]): Promise<any> {

  // }

  // async eth_getFilterChanges(params: any[]): Promise<any> {

  // }

  // async eth_getFilterLogs(params: any[]): Promise<any> {

  // }

  async eth_getLogs(params: any[]): Promise<Log[]> {
    validate([{ type: 'object' }], params);
    const result = await this.#provider.getLogs(params[0]);
    return hexlifyRpcResult(result);
  }
Example #8
Source File: endpoint.test.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
expectLogsEqual = (a: Log[], b: Log[]): boolean => {
  expect(a.length).to.greaterThan(0);
  expect(a.length).to.equal(b.length);
  expect(
    a.every(({ transactionHash: t0, logIndex: l0 }) =>
      b.find(({ transactionHash: t1, logIndex: l1 }) => t0 === t1 && parseInt(l0) === parseInt(l1))
    )
  );
}
Example #9
Source File: subqlProvider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
getFilteredLogs = async (filter: Filter & FilterByBlockHash): Promise<Log[]> => {
    const queryFilter = getLogsQueryFilter(filter);

    const res = await this.queryGraphql(`
      query {
        logs${queryFilter} {
          ${LOGS_NODES}
        }
      }
    `);

    return adaptLogs(res.logs!.nodes as LogGQL[]);
  };
Example #10
Source File: subqlProvider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
getAllLogs = async (): Promise<Log[]> => {
    const res = await this.queryGraphql(`
      query {
        logs {
          ${LOGS_NODES}
        }
      }
    `);

    return adaptLogs(res.logs!.nodes as LogGQL[]);
  };
Example #11
Source File: logs.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
filterLog = (log: Log, filter: any): boolean => {
  const { address: targetAddr, topics: targetTopics } = filter;

  if (targetAddr) {
    if (typeof targetAddr === 'string') {
      if (log.address.toLowerCase() !== targetAddr.toLowerCase()) return false;
    } else if (Array.isArray(targetAddr)) {
      if (!targetAddr.map((x: string) => x.toLowerCase()).includes(log.address.toLowerCase())) return false;
    }
  }

  if (targetTopics?.length > 0) {
    if (!log.topics?.length) return false;

    const _targetTopics = targetTopics
      .flat()
      .filter((x: any) => x)
      .map((x: string) => x.toLowerCase());
    for (const t of log.topics) {
      if (_targetTopics.includes(t.toLowerCase())) return true;
    }

    return false;
  }

  return true;
}
Example #12
Source File: DataProvider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
/**
   *
   * @param filter The filter to apply to the logs
   * @param resolveBlockNumber The block to retrieve the logs from, defaults
   * to the head
   * @returns A promise that resolves to an array of filtered logs
   */
  abstract getLogs(
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    filter: any,
    resolveBlockNumber: (blockTag?: BlockTag | Promise<BlockTag>) => Promise<number | undefined>
  ): Promise<Array<Log>>;
Example #13
Source File: endpoint.test.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
logsEq = (a: Log[], b: Log[]): boolean =>
  a.length === b.length &&
  a.every(({ transactionHash: t0, logIndex: l0 }) =>
    b.find(({ transactionHash: t1, logIndex: l1 }) => t0 === t1 && parseInt(l0) === parseInt(l1))
  )
Example #14
Source File: index.ts    From defillama-sdk with GNU Affero General Public License v3.0 5 votes vote down vote up
// SMALL INCOMPATIBILITY: On the old API we don't return ids but we should
export async function getLogs(params: {
  target: Address;
  topic: string;
  keys: string[]; // This is just used to select only part of the logs
  fromBlock: number;
  toBlock: number; // DefiPulse's implementation is buggy and doesn't take this into account
  topics?: string[]; // This is an outdated part of DefiPulse's API which is still used in some old adapters
  chain?: Chain;
}) {
  if(params.toBlock === undefined || params.fromBlock === undefined){
    throw new Error("toBlock and fromBlock need to be defined in all calls to getLogs")
  }
  const filter = {
    address: params.target,
    topics: params.topics ?? [utils.id(params.topic)],
    fromBlock: params.fromBlock,
    toBlock: params.toBlock, // We don't replicate Defipulse's bug because the results end up being the same anyway and hopefully they'll eventually fix it
  };
  let logs: Log[] = [];
  let blockSpread = params.toBlock - params.fromBlock;
  let currentBlock = params.fromBlock;
  while (currentBlock < params.toBlock) {
    const nextBlock = Math.min(params.toBlock, currentBlock + blockSpread);
    try {
      const partLogs = await getProvider(params.chain).getLogs({
        ...filter,
        fromBlock: currentBlock,
        toBlock: nextBlock,
      });
      logs = logs.concat(partLogs);
      currentBlock = nextBlock;
    } catch (e) {
      if (blockSpread >= 2e3) {
        // We got too many results
        // We could chop it up into 2K block spreads as that is guaranteed to always return but then we'll have to make a lot of queries (easily >1000), so instead we'll keep dividing the block spread by two until we make it
        blockSpread = Math.floor(blockSpread / 2);
      } else {
        throw e;
      }
    }
  }
  if (params.keys.length > 0) {
    if (params.keys[0] !== "topics") {
      throw new Error("Unsupported");
    }
    return {
      output: logs.map((log) => log.topics),
    };
  }
  return {
    output: logs,
  };
}
Example #15
Source File: logs.ts    From useDApp with MIT License 5 votes vote down vote up
/**
 * @internal Intended for internal use - use it on your own risk
 */
export function decodeLogs<T extends TypedContract, EN extends ContractEventNames<T>>(
  filter: TypedFilter | Falsy,
  result: Log[] | Falsy | Error
): LogsResult<T, EN> {
  if (!result || !filter) {
    return undefined
  }
  try {
    if (result instanceof Error) {
      return {
        value: undefined,
        error: result,
      }
    }

    const decodedLogs: Awaited<DetailedEventRecord<T, EN>>[] = []

    for (const log of result) {
      const data = filter.contract.interface.decodeEventLog(filter.event, log.data, log.topics) as EventRecord<T, EN>

      decodedLogs.push({
        data,
        blockNumber: log.blockNumber,
        blockHash: log.blockHash,
        transactionIndex: log.transactionIndex,
        transactionHash: log.transactionHash,
        removed: log.removed,
      })
    }

    return {
      value: decodedLogs,
      error: undefined,
    }
  } catch (error) {
    return {
      value: undefined,
      error: error as Error,
    }
  }
}
Example #16
Source File: EthereumNodeClient.d.ts    From tx2uml with MIT License 5 votes vote down vote up
static parseTransferEvents(logs: Array<Log>): Transfer[];
Example #17
Source File: transaction.d.ts    From tx2uml with MIT License 5 votes vote down vote up
static parseTransactionLogs(logs: Array<Log>, contracts: Contracts): void;
Example #18
Source File: logs.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
adaptLogs = (logs: LogGQL[]): Log[] =>
  logs.map((log) => ({
    ...log,
    data: log.data || ''
  }))
Example #19
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
// Bloom-filter Queries
  getLogs = async (rawFilter: Filter & FilterByBlockHash): Promise<Log[]> => {
    if (!this.subql) {
      return logger.throwError(
        'missing subql url to fetch logs, to initialize base provider with subql, please provide a subqlUrl param.'
      );
    }

    const { fromBlock, toBlock, blockHash } = rawFilter;
    const filter = { ...rawFilter };

    if (blockHash && (fromBlock || toBlock)) {
      return logger.throwError(
        '`fromBlock` and `toBlock` is not allowed in params when `blockHash` is present',
        Logger.errors.INVALID_ARGUMENT,
        {
          blockHash,
          fromBlock,
          toBlock
        }
      );
    }

    if (blockHash) {
      const blockNumber = (await this._getBlockHeader(blockHash)).number.toNumber();

      filter.fromBlock = blockNumber;
      filter.toBlock = blockNumber;
    } else {
      const fromBlockNumber = await this._getBlockNumberFromTag(fromBlock ?? 'latest');
      const toBlockNumber = await this._getBlockNumberFromTag(toBlock ?? 'latest');

      filter.fromBlock = fromBlockNumber;
      filter.toBlock = toBlockNumber;
    }

    const filteredLogs = await this.subql.getFilteredLogs(filter);

    return filteredLogs.map((log) => this.formatter.filterLog(log));
  };
Example #20
Source File: logs.test.ts    From useDApp with MIT License 4 votes vote down vote up
describe('decodeLogs', () => {
  const mockProvider = new MockProvider()
  const [deployer] = mockProvider.getWallets()
  let token: Contract

  beforeEach(async () => {
    token = await deployMockToken(deployer)
  })

  it('Returns undefined if the filter and result are undefined', () => {
    expect(decodeLogs(undefined, undefined)).to.be.undefined
  })

  it('Returns undefined if the result is undefined', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    expect(decodeLogs(filter, undefined)).to.be.undefined
  })

  it('Returns undefined if the filter is undefined', () => {
    expect(decodeLogs(undefined, [])).to.be.undefined
  })

  it('Returns an error if passed an error as the result', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const error = Error('')

    const decodedLogs = decodeLogs(filter, error)

    expect(decodedLogs?.error).to.equal(error)
    expect(decodedLogs?.value).to.be.undefined
  })

  it('Returns an empty array when passed an empty array of logs', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const logs: Log[] = []

    const decodedLogs = decodeLogs(filter, logs)

    expect(decodedLogs?.error).to.be.undefined
    expect(decodedLogs?.value).to.be.empty
  })

  it('Returns an error when the event topic is a mismatch', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const logs: Log[] = [
      {
        address: token.address,
        topics: [
          ethers.utils.id('Transfer2(address,address,uint256)'),
          ethers.utils.hexZeroPad(AddressZero, 32),
          ethers.utils.hexZeroPad(AddressZero, 32),
        ],
        data: ethers.utils.hexZeroPad(AddressZero, 32),
        blockHash: '0x0',
        blockNumber: 0,
        logIndex: 0,
        transactionIndex: 0,
        transactionHash: '0x0',
        removed: false,
      },
    ]

    const decodedLogs = decodeLogs(filter, logs)

    expect(decodedLogs?.value).to.be.undefined
    expect(decodedLogs?.error).to.be.a('Error')
  })

  it('Works when passed valid logs', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const from = AddressZero
    const to = deployer.address
    const value = BigNumber.from(1)
    const blockHash = '0x0'
    const blockNumber = 1
    const logIndex = 2
    const transactionIndex = 3
    const removed = true
    const transactionHash = '0x11'

    const logs: Log[] = [
      {
        address: token.address,
        topics: [
          ethers.utils.id('Transfer(address,address,uint256)'),
          ethers.utils.hexZeroPad(from, 32),
          ethers.utils.hexZeroPad(to, 32),
        ],
        data: ethers.utils.hexZeroPad(ethers.utils.hexlify(value), 32),
        blockHash,
        blockNumber,
        logIndex,
        transactionIndex,
        transactionHash,
        removed,
      },
      {
        address: token.address,
        topics: [
          ethers.utils.id('Transfer(address,address,uint256)'),
          ethers.utils.hexZeroPad(from, 32),
          ethers.utils.hexZeroPad(to, 32),
        ],
        data: ethers.utils.hexZeroPad(ethers.utils.hexlify(value), 32),
        blockHash,
        blockNumber,
        logIndex,
        transactionIndex,
        transactionHash,
        removed,
      },
    ]

    const decodedLogs = decodeLogs(filter, logs)

    expect(decodedLogs?.error).to.be.undefined

    const theLogs = decodedLogs as LogsResult<typeof token, 'Transfer'>

    expect(theLogs?.value).to.have.length(2)

    expect(theLogs?.value![0].blockHash).to.equal(blockHash)
    expect(theLogs?.value![0].blockNumber).to.equal(blockNumber)
    expect(theLogs?.value![0].removed).to.equal(removed)
    expect(theLogs?.value![0].transactionIndex).to.equal(transactionIndex)
    expect(theLogs?.value![0].transactionHash).to.equal(transactionHash)
    expect(theLogs?.value![0].data.from).to.equal(from)
    expect(theLogs?.value![0].data.to).to.equal(to)
    expect(theLogs?.value![0].data.value).to.equal(value)
  })
})