@ethersproject/abstract-provider#Filter TypeScript Examples

The following examples show how to use @ethersproject/abstract-provider#Filter. 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: logs.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
getLogsQueryFilter = (filter: Filter): string => {
  const { fromBlock, toBlock, address, topics } = filter;
  if (!isAnyDefined([fromBlock, toBlock, address, topics])) {
    return '';
  }

  const addressFilter = _getAddressFilter(address);
  const blockNumberFilter = _getBlockNumberFilter(fromBlock, toBlock);
  const topicsFilter = _getTopicsFilter(topics);

  const queryFilter = `(filter: {
    ${addressFilter}
    ${blockNumberFilter}
    ${topicsFilter}
  })`;

  return queryFilter;
}
Example #2
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 #3
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 #4
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 #5
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 #6
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 encodeFilterData(
  filter: TypedFilter | Falsy,
  fromBlock?: BlockTag,
  toBlock?: BlockTag,
  blockHash?: string
): Filter | FilterByBlockHash | Falsy | Error {
  if (!filter) {
    return undefined
  }
  const { contract, event, args } = filter
  if (!contract.address || !event) {
    warnOnInvalidFilter(filter)
    return undefined
  }
  try {
    const encodedTopics = contract.interface.encodeFilterTopics((event as unknown) as utils.EventFragment, args)

    if (blockHash) {
      return {
        address: contract.address,
        topics: encodedTopics,
        blockHash: blockHash,
      } as FilterByBlockHash
    } else {
      return {
        address: contract.address,
        topics: encodedTopics,
        fromBlock: fromBlock ?? 0,
        toBlock: toBlock ?? 'latest',
      } as Filter
    }
  } catch (e) {
    if (e instanceof Error) {
      return e as Error
    } else {
      warnOnInvalidFilter(filter)
      return undefined
    }
  }
}
Example #7
Source File: logs.test.ts    From useDApp with MIT License 4 votes vote down vote up
describe('encodeFilterData', () => {
  const mockProvider = new MockProvider()
  const [deployer] = mockProvider.getWallets()
  let token: Contract

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

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

  it('Returns FilterByBlockHash when blockHash is valid', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const encodedFilterData = encodeFilterData(filter, undefined, undefined, '0x0') as FilterByBlockHash

    expect(encodedFilterData['blockHash']).to.not.be.undefined
  })

  it('Returns FilterByBlockHash when blockHash, toBlock, and fromBlock are valid', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const encodedFilterData = encodeFilterData(filter, 0, 'latest', '0x0') as FilterByBlockHash

    expect(encodedFilterData['blockHash']).to.not.be.undefined
  })

  it('Returns Filter when toBlock and fromBlock are valid but blockHash is invalid', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [],
    }

    const encodedFilterData = encodeFilterData(filter, 0, 'latest', undefined) as Filter

    expect(encodedFilterData['toBlock']).to.not.be.undefined
  })

  it('Returns an error when passed a non-existant event', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer2',
      args: [],
    }

    const encodedFilterData = encodeFilterData(filter, 0, 'latest')

    expect(encodedFilterData).to.be.a('Error')
  })

  it('Returns an error when passed an arg for an un-indexed parameter', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [AddressZero, AddressZero, 10],
    }

    const encodedFilterData = encodeFilterData(filter, 0, 'latest')

    expect(encodedFilterData).to.be.a('Error')
  })

  it('Returns an error when passed too many args', () => {
    const filter: TypedFilter = {
      contract: token,
      event: 'Transfer',
      args: [AddressZero, AddressZero, null, AddressZero],
    }

    const encodedFilterData = encodeFilterData(filter, 0, 'latest')

    expect(encodedFilterData).to.be.a('Error')
  })
})
Example #8
Source File: useRawLogs.test.ts    From useDApp with MIT License 4 votes vote down vote up
describe('useRawLogs', () => {
  const mockProvider = new MockProvider()
  const secondMockProvider = new MockProvider({ ganacheOptions: { _chainIdRpc: SECOND_TEST_CHAIN_ID } as any })
  const [deployer, receiver] = mockProvider.getWallets()
  const [secondDeployer] = secondMockProvider.getWallets()
  const eventTopic = ethers.utils.id('Transfer(address,address,uint256)')
  let token: Contract
  let secondToken: Contract

  beforeEach(async () => {
    token = await deployMockToken(deployer)
    secondToken = await deployMockToken(secondDeployer, SECOND_MOCK_TOKEN_INITIAL_BALANCE)
  })

  async function sendToken(signer: ethers.Wallet, to: string, amount: BigNumber) {
    const { result, waitForCurrent, waitForNextUpdate } = await renderWeb3Hook(
      () =>
        useSendTransaction({
          signer,
        }),
      { mockProvider }
    )

    await waitForNextUpdate()

    const txData = ERC20MockInterface.encodeFunctionData('transfer(address,uint)', [to, amount])

    const tx: TransactionRequest = {
      to: token.address,
      value: BigNumber.from(0),
      data: txData,
      gasPrice: 0,
    }

    await result.current.sendTransaction(tx)

    await waitForCurrent((val) => val.state !== undefined)
    expect(result.current.state.status).to.eq('Success')
  }

  function extractAddress(address: string) {
    let result: string
    result = hexStripZeros(address)
    while (result.length != 42) result = '0x0' + result.substring(2)

    return result
  }

  it('Can get only the recent token transfer log', async () => {
    const blockNumber = await mockProvider.getBlockNumber()

    const from = deployer
    const to = receiver

    const fromAddress = from.address
    const toAddress = to.address
    const amount = BigNumber.from(1)

    await sendToken(from, toAddress, amount)

    const filter: Filter = {
      address: token.address,
      fromBlock: blockNumber + 1,
      toBlock: blockNumber + 2,
      topics: [eventTopic],
    }

    const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })

    await waitForCurrent((val) => val !== undefined)
    expect(result.error).to.be.undefined

    expect(result.current?.length).to.equal(1, 'Number of logs')

    const log = result.current![0]

    expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
    expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(fromAddress), 'From')
    expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(toAddress), 'To')

    const decodedData = defaultAbiCoder.decode(['uint'], log.data)

    expect(decodedData[0]).to.equal(amount, 'Amount')
  })

  it('Can get all token transfer logs', async () => {
    const from = deployer
    const to = receiver

    const fromAddress = from.address
    const toAddress = to.address
    const amount = BigNumber.from(1)

    await sendToken(from, toAddress, amount)

    const filter: Filter = {
      address: token.address,
      fromBlock: 0,
      toBlock: 'latest',
      topics: [eventTopic],
    }

    const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })

    await waitForCurrent((val) => val !== undefined)
    expect(result.error).to.be.undefined

    expect(result.current?.length).to.equal(2, 'Number of logs')

    // Mint transfer event
    const log1 = result.current![0]

    expect(log1.topics[0]).to.equal(eventTopic, 'Event topic')
    expect(getAddress(extractAddress(log1.topics[1]))).to.equal(getAddress(AddressZero), 'From')
    expect(getAddress(extractAddress(log1.topics[2]))).to.equal(getAddress(deployer.address), 'To')

    const decodedData1 = defaultAbiCoder.decode(['uint'], log1.data)

    expect(decodedData1[0]).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')

    // Recent transfer transaction log
    const log = result.current![1]

    expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
    expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(fromAddress), 'From')
    expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(toAddress), 'To')

    const decodedData = defaultAbiCoder.decode(['uint'], log.data)

    expect(decodedData[0]).to.equal(amount, 'Amount')
  })

  it('Can get the mint transfer log', async () => {
    const filter: Filter = {
      address: token.address,
      fromBlock: 0,
      toBlock: 'latest',
      topics: [eventTopic],
    }

    const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })

    await waitForCurrent((val) => val !== undefined)
    expect(result.error).to.be.undefined

    expect(result.current?.length).to.equal(1, 'Number of logs')

    const log = result.current![0]

    expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
    expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(AddressZero), 'From')
    expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(deployer.address), 'To')

    const decodedData = defaultAbiCoder.decode(['uint'], log.data)

    expect(decodedData[0]).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
  })

  it('Can get the mint transfer log on the alternative chain', async () => {
    const filter: Filter = {
      address: secondToken.address,
      fromBlock: 0,
      toBlock: 'latest',
      topics: [eventTopic],
    }

    const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), {
      mockProvider: secondMockProvider,
    })

    await waitForCurrent((val) => val !== undefined)
    expect(result.error).to.be.undefined

    expect(result.current?.length).to.equal(1, 'Number of logs')

    const log = result.current![0]

    expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
    expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(AddressZero), 'From')
    expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(secondDeployer.address), 'To')

    const decodedData = defaultAbiCoder.decode(['uint'], log.data)

    expect(decodedData[0]).to.equal(SECOND_MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
  })

  it('Works if there are no logs', async () => {
    const filter: Filter = {
      address: secondToken.address, // Token on the other chain... doesn't exist so there should be no logs
      fromBlock: 0,
      toBlock: 'latest',
      topics: [eventTopic],
    }

    const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })

    await waitForCurrent((val) => val !== undefined)
    expect(result.error).to.be.undefined
    expect(result.current?.length).to.equal(0, 'Number of logs')
  })
})