Is anyone using filters with the Harmony API?

According to the Harmony API, we can use filters to query blocks, pending transactions and specific addresses. I’m trying to use a filter but it looks like i always get a Filter not found error. I’m wondering if this is a bug or if i’m doing something wrong.

import json
import requests

r = requests.post('https://api.s0.t.hmny.io/', json={"jsonrpc":"2.0","method":"eth_newPendingTransactionFilter","params":[],"id":1})

filter_1 = r.json()['result']

r = requests.post('https://api.s0.t.hmny.io/', json={
	    "jsonrpc": "2.0",
	    "method": "hmy_getFilterLogs",
	    "params": [
	       filter_1
	    ],
	    "id": 1
		}
	)

print(r.json())

I have a working example for you… It is an extension of the previous code you posted…

but I never find anything ‘pending’ so far… I think the TX is too quick to find lol

From what I gather from your example, you need to set the ID as 73 when you set the filter.

from web3 import Web3, exceptions
import time

main_net = 'https://rpc.s0.t.hmny.io'
wss_url = 'wss://ws.s0.t.hmny.io'
# w3 = Web3(Web3.HTTPProvider(main_net))
w3 = Web3(Web3.WebsocketProvider(wss_url))

p_key = ''
address = w3.eth.account.privateKeyToAccount(p_key).address
print(address)

send_to_address = ''

chain_id = 1666600000
gas_price = 1000000000
gas = 25000
min_gas = 0.000025

from requests import post

def call_rpc_single_page(
    method: str,
    rpc_endpoint: str,
    params: list = [],
    _id: int = 1,

) -> None:

    headers = {
            'Content-Type': 'application/json'
        }

    d = {"jsonrpc": "2.0", "method": method, "params": params, "id": str(_id)}
    data = post(rpc_endpoint, json=d, headers=headers).json()

    return data

create_filter = call_rpc_single_page(
    "eth_newPendingTransactionFilter",
    main_net,
    [],
    _id = 73,
)

# Set Filter before Tx..
print(create_filter)
if create_filter:
    pending_filter = create_filter['result']


nonce = w3.eth.getTransactionCount(address)

tx = {	
		'chainId': chain_id,
		'nonce': nonce,
		'value': 0,
		'gas': gas,
		'gasPrice': gas_price,
		'data': '',
		'to': Web3.toChecksumAddress(send_to_address),
	}

signed_tx = w3.eth.account.signTransaction(tx, p_key)

t_hash = str(w3.eth.sendRawTransaction(signed_tx.rawTransaction).hex())
print(t_hash)

while True:
    data = call_rpc_single_page(
        "eth_getFilterChanges",
        main_net,
        [pending_filter],
    )
    if data.get('result'):
        # print(data['result'])
        for x in data['result']:
            # print(x)
            if x == t_hash:
                print(f'Found TX  ::  {x}')


Remember, the API is based upon ETH so you can find info from here:

https://eth.wiki/json-rpc/API#eth_newpendingtransactionfilter

Thanks a lot for your help! It’s weird, because my response is always this {'jsonrpc': '2.0', 'id': 1, 'error': {'code': -32000, 'message': 'filter not found'}}. Can you paste the full json response you get when you query eth_getFilterChanges (after the while loop)?

My bad, it looks like sometimes it returns filter not found, while other times it returns a list of transaction hashes, which is what i was expecting

1 Like

That is what this is for :slight_smile:

if data.get('result'):

Thanks! One thing: the pendingTransactionsFilter returns hashes, i’m in a condition where i need transaction’s data too (from, to, input), do you know if there is any way to get that or is getPendingTransactions the only way for now?

hash_info = w3.eth.getTransaction(t_hash)
parsed = dict(hash_info)
print(parsed)

returns:

{
    "blockHash": "0x74fdf522ebb757e8cc7cfce838d6a0482e1e03f1ab852e2e324d5e8c9e0658f0",
    "blockNumber": 19972867,
    "from": "0xF88b361E05a504D9ef34FFeE0E6A5137eba219ca",
    "gas": 25000,
    "gasPrice": 1000000000,
    "hash": "0xcaf2e8bb1c0291784eb60c59cc51a71821bcfb03dfa3170039ae31b0d6cca291",
    "input": "0x",
    "nonce": 3380,
    "r": "0xb67511ad05fc030da48d44d3530bed011bbf5d482afdbb2889d0caa5f6cff512",
    "s": "0x34a99040b589587287064992e6c95e094d4e4203f2da21162c39b92c4e948c3d",
    "timestamp": "0x61a7cb39",
    "to": "0xfAFfb33B924C33381dee35D445013D3200249572",
    "transactionIndex": 108,
    "v": 3333200035,
    "value": 1
}

1 Like

Thanks, the only problem is that getTransaction only works when the transaction is mined, if the transaction is still pending it won’t work

Do you have a pending transaction hash?

I don’t right now, but if you make a transaction and immediately later try to search it with getTransaction, it will return a Transaction not found until the tx gets mined

Try this… It uses the pending filter to find the hash. . It is the ETH_HASH we needed to check…

This script will create a TX and then find it in the Pending TX’s list.

from web3 import Web3, exceptions
from requests import post

main_net = 'https://rpc.s0.t.hmny.io'
wss_url = 'wss://ws.s0.t.hmny.io'
# w3 = Web3(Web3.HTTPProvider(main_net))
w3 = Web3(Web3.WebsocketProvider(wss_url))

p_key = ''
address = w3.eth.account.privateKeyToAccount(p_key).address
print(address)

send_to_address = ''

chain_id = 1666600000
gas_price = 1000000000
gas = 25000
min_gas = 0.000025

def call_rpc_single_page(
    method: str,
    rpc_endpoint: str,
    params: list = [],
    _id: int = 1,

) -> None:

    headers = {
            'Content-Type': 'application/json'
        }

    d = {"jsonrpc": "2.0", "method": method, "params": params, "id": str(_id)}
    data = post(rpc_endpoint, json=d, headers=headers).json()

    return data

def create_filter() -> str:
    create_filter = call_rpc_single_page(
        "eth_newPendingTransactionFilter",
        main_net,
        [],
        _id = 73,
    )

    print(create_filter)
    if create_filter.get('result'):
        pending_filter = create_filter['result']
    return pending_filter

def send_tx(address: str) -> str:
    nonce = w3.eth.getTransactionCount(address)

    tx = {	
            'chainId': chain_id,
            'nonce': nonce,
            'value': 1,
            'gas': gas,
            'gasPrice': gas_price,
            'data': '',
            'to': Web3.toChecksumAddress(send_to_address),
        }

    signed_tx = w3.eth.account.signTransaction(tx, p_key)

    t_hash = str(w3.eth.sendRawTransaction(signed_tx.rawTransaction).hex())
    return t_hash


def find_pending_tx(t_hash: str) -> dict:
    retry = []
    while True:
        data = call_rpc_single_page(
            "eth_getFilterChanges",
            main_net,
            [pending_filter],
        )
        # print(data)
        if data.get('result'):
            # print(data['result'])
            data = data['result']
            data += retry
            retry = []
            for x in data:
                # print(x)
                try:
                    hash_info = w3.eth.getTransaction(x)
                    tx_data = dict(hash_info)
                    eth_hash = tx_data['hash'].hex()
                    
                    if t_hash == eth_hash:
                        print(f'Found TX  ::  {t_hash}')
                        return tx_data
                except exceptions.TransactionNotFound:
                    retry += [x]


pending_filter = create_filter()
t_hash = send_tx(address)
found = find_pending_tx(t_hash)   

for k, v in found.items():
    try:
        print(f'{k} : {v.hex()}')     
    except AttributeError:
        print(f'{k} : {v}') 

IT will print the following and as you can see thet blockHash , blockNumber and transactionIndex are returning None

blockHash : None
blockNumber : None
from : 0xF88b361E05a504D9ef34FFeE0E6A5137eba219ca
gas : 25000
gasPrice : 1000000000
hash : 0x6092b0291ef99ba28d7a039f2e0ef48dbf2244c656c510057a870ea2e8d70f02
input : 0x
nonce : 3405
r : 0x11c3bf4a05d04d49ebd8c4a804aedb15301395f72faba631c3d4e096fcaadddc
s : 0x205dcb70567bea76c4f89b95719e6293e0aa8aa43aa5b8bc8832741ea206d431
timestamp : 0x0
to : 0xfAFfb33B924C33381dee35D445013D3200249572
transactionIndex : None
v : 3333200036
value : 1

Waiting a little longer and we can query the Hash as normal


t = '0x6092b0291ef99ba28d7a039f2e0ef48dbf2244c656c510057a870ea2e8d70f02'

hash_info = w3.eth.getTransaction(t)
found = dict(hash_info)

for k, v in found.items():
    try:
        print(f'{k} : {v.hex()}')     
    except AttributeError:
        print(f'{k} : {v}') 

And we see the None fields are completed with Data now that the Transaction has gone through.

blockHash : 0x2f39ecc7bea2ae39172e24a10f55dcf64c3d700fcc380aaf7c8539c7a9e9d360
blockNumber : 19988163
from : 0xF88b361E05a504D9ef34FFeE0E6A5137eba219ca
gas : 25000
gasPrice : 1000000000
hash : 0x6092b0291ef99ba28d7a039f2e0ef48dbf2244c656c510057a870ea2e8d70f02
input : 0x
nonce : 3405
r : 0x11c3bf4a05d04d49ebd8c4a804aedb15301395f72faba631c3d4e096fcaadddc
s : 0x205dcb70567bea76c4f89b95719e6293e0aa8aa43aa5b8bc8832741ea206d431
timestamp : 0x61a8844d
to : 0xfAFfb33B924C33381dee35D445013D3200249572
transactionIndex : 76
v : 3333200036
value : 1

I hope this helps…

1 Like

Wow, you’re awesome @Maffaz! Thanks a lot, really, that was incredibly helpful

1 Like

No problem… Happy to be able to help.

1 Like