-
Notifications
You must be signed in to change notification settings - Fork 0
Indexer code #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Indexer code #4
Conversation
schema.sql
Outdated
|
|
||
| CREATE TABLE | ||
| list_registration ( | ||
| id SERIAL PRIMARY KEY, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change this to INT rather than SERIAL as we will want to manually set it as per registration ID on list contract (which will be an int, but may not increment identically and so we want to make sure there are no discrepancies)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
registration ID is not returned in the register action, the id in the action result is the project id provided by the user, or the signerID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the Registration returned in the new Lists contract? I think since the Lists contract will be out within a day or so and all existing projects on registry.potlock.near will be migrated there via the register method, we don't have to account for the current registry contract.
|
|
||
| CREATE TABLE | ||
| pot ( | ||
| id VARCHAR PRIMARY KEY, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to SERIAL
| FOREIGN KEY (owner_id) REFERENCES account (id), | ||
| FOREIGN KEY (chef_id) REFERENCES account (id), | ||
| FOREIGN KEY (base_currency) REFERENCES account (id) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
cooldown_period_ms INT NOT NULL
account_id VARCHAR NOT NULL
FOREIGN KEY (account_id) REFERENCES account (id)
schema.sql
Outdated
| deployed_at TIMESTAMP NOT NULL, | ||
| source_metadata VARCHAR NOT NULL, | ||
| owner_id VARCHAR NOT NULL, | ||
| chef_id VARCHAR NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for consistency and clarity's sake, either remove this NULL and other instances (as it is the default), or use it consistently across all tables for any nullable columns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my personal preference would be to remove NULL as I think it's easier to read
schema.sql
Outdated
| pot_id INT NOT NULL, | ||
| applicant_id VARCHAR NOT NULL, | ||
| message TEXT, | ||
| current_status ENUM('Pending', 'Approved', 'Rejected', 'InReview') NOT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's actually change this to just status
schema.sql
Outdated
| current_status ENUM('Pending', 'Approved', 'Rejected', 'InReview') NOT NULL, | ||
| submitted_at TIMESTAMP NOT NULL, | ||
| last_updated_at TIMESTAMP, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
schema.sql
Outdated
| updated_at TIMESTAMP, | ||
| registrant_notes TEXT, | ||
| admin_notes TEXT, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
schema.sql
Outdated
| notes TEXT, | ||
| status ENUM('Pending', 'Approved', 'Rejected', 'InReview') NOT NULL, | ||
| reviewed_at TIMESTAMP NOT NULL, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
schema.sql
Outdated
| id SERIAL PRIMARY KEY, | ||
| recipient_id VARCHAR NOT NULL, | ||
| amount VARCHAR NOT NULL, | ||
| amount_usd DECIMAL(10, 2), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NB: this should be set when the payout is actually paid out (so it is the USD amount at the time of the payout)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so make field name more descriptive of the instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No changes needed, was just making a note
| paid_at TIMESTAMP, | ||
| tx_hash VARCHAR, | ||
| FOREIGN KEY (recipient_id) REFERENCES account (id) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
FOREIGN KEY (ft_id) REFERENCES account (id)
schema.sql
Outdated
| amount_usd DECIMAL(10, 2), | ||
| ft_id VARCHAR NOT NULL, | ||
| paid_at TIMESTAMP, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
not actually sure that we need this, it's a little confusing as it could be the hash when the payout is set, or the hash when it is paid out
schema.sql
Outdated
| created_at TIMESTAMP NOT NULL, | ||
| message TEXT, | ||
| resolved BOOL NOT NULL, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
schema.sql
Outdated
| pot_id INT NOT NULL, | ||
| created_at TIMESTAMP NOT NULL, | ||
| message TEXT NOT NULL, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
schema.sql
Outdated
| -- Table donation | ||
| CREATE TABLE | ||
| donation ( | ||
| id SERIAL PRIMARY KEY, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to INT instead of SERIAL so we can set manually and make sure it stays in sync with Donation ID on contract
schema.sql
Outdated
| total_amount_usd DECIMAL(10, 2), | ||
| net_amount VARCHAR NOT NULL, | ||
| net_amount_usd DECIMAL(10, 2), | ||
| ft_id VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
| FOREIGN KEY (donor_id) REFERENCES account (id), | ||
| FOREIGN KEY (pot_id) REFERENCES pot (id), | ||
| FOREIGN KEY (recipient_id) REFERENCES account (id) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
FOREIGN KEY (ft_id) REFERENCES account (id)
FOREIGN KEY (referrer_id) REFERENCES account (id)
FOREIGN KEY (chef_id) REFERENCES account (id)
schema.sql
Outdated
| chef_id VARCHAR, | ||
| chef_fee VARCHAR, | ||
| chef_fee_usd DECIMAL(10, 2), | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
| CREATE TABLE | ||
| pot_admin ( | ||
| pot_id INT NOT NULL, | ||
| admin_id VARCHAR NOT NULL, | ||
| PRIMARY KEY (pot_id, admin_id), | ||
| FOREIGN KEY (pot_id) REFERENCES pot (id), | ||
| FOREIGN KEY (admin_id) REFERENCES account (id) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this up so it's under pot table definition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't understand, why should this be moved to pots?, it's more like a many to many junction table, since an account can be admin on different pots, and pots can have many admins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No no I was just saying, all the pot-related tables should be grouped together for ease of reading & understanding the schema file
| 'Add_List_Admin', | ||
| 'Remove_List_Admin' | ||
| ) NOT NULL | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
FOREIGN KEY (signer_id) REFERENCES account (id)
FOREIGN KEY (receiver_id) REFERENCES account (id)
schema.sql
Outdated
| receiver_id VARCHAR NOT NULL, | ||
| timestamp TIMESTAMP NOT NULL, | ||
| action_result VARCHAR, | ||
| tx_hash VARCHAR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add NOT NULL
| 'Blacklisted' | ||
| ) NOT NULL, | ||
| FOREIGN KEY (owner_id) REFERENCES account (id) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
created_at TIMESTAMP NOT NULL
updated_at TIMESTAMP
schema.sql
Outdated
|
|
||
| -- pot index | ||
|
|
||
| -- CREATE INDEX "deploy_time_idx" ON pot (deployed_at); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add this back in
| -- CREATE INDEX idx_pot_payout_ft_id ON pot_payout (ft_id); | ||
| CREATE INDEX idx_pot_payout_paid_at ON pot_payout (paid_at); | ||
|
|
||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
-
indexes for account (
total_donations_received_usd,total_matching_pool_allocations_usd,total_donated_usd,donors_count- we will almost certainly want to query ordered results based on these columns) -
indexes for list on
created_atandupdated_at -
composite index for list registration/status:
CREATE INDEX idx_list_id_status ON list_registration(list_id, status); -
composite indexes for pot application & matching round start/end:
CREATE INDEX idx_application_period ON pot(application_start, application_end);
CREATE INDEX idx_matching_period ON pot(matching_round_start, matching_round_end);-
additional
potindexes ondeployed_at,total_matching_pool,total_matching_pool_usd,total_public_donations,total_public_donations_usd,public_donations_count -
composite index for
pot_applicationonpot_id/status -
pot_application_reviewindex onreviewer_id -
additional
pot_payoutindexes onamountandamount_usd -
pot_payout_challengeindexes onpot_idandchallenger_id, plus composite index forpot_id+created_at -
pot_payout_challenge_admin_responseindexes onadmin_idandchallenge_id -
additional
donationindexes ontotal_amount,total_amount_usd,matching_pool,recipient_id,referrer_id&chef_id -
additional
activityindexes onsigner_id,recipient_idandtype
schema.sql
Outdated
| CREATE INDEX idx_pot_application_start ON pot (application_start); | ||
| CREATE INDEX idx_pot_application_end ON pot (application_end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove these and replace with composite indexes as per example below
|
|
||
| -- CREATE INDEX idx_pot_payout_recipient_id ON pot_payout (recipient_id); | ||
| -- CREATE INDEX idx_pot_payout_ft_id ON pot_payout (ft_id); | ||
| CREATE INDEX idx_pot_payout_paid_at ON pot_payout (paid_at); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this up with the other pot_payout indexes
|
|
||
| } | ||
| } else { | ||
| potUpdate["public_donations_count"] = pot.public_donations_count || 0 + 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| ? "Donate_Pot_Matching_Pool" | ||
| : "Donate_Pot_Public", | ||
| action_result: recipient, | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change from receipt hash to tx hash
indexer.ts
Outdated
| : donation.matching_pool | ||
| ? "Donate_Pot_Matching_Pool" | ||
| : "Donate_Pot_Public", | ||
| action_result: recipient, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about this. what do you think about potentially storing the entire raw result in this field? that way the client can get the success value, or the receiver, or whatever else they may want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could do that, but not all actions actually have a result value, i think. but i'll change it to that
| break; | ||
|
|
||
| // this is a form of donation where user calls donate on a pot | ||
| case "handle_protocol_fee_callback": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably listen to the process_donation callback which is at the end of the callback chain and returns the new donation
indexer.ts
Outdated
| args, | ||
| action.receiverId, | ||
| action.signerId, | ||
| "handle_protocol_fee_callback", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe change to "pot" for clarity
indexer.ts
Outdated
| args, | ||
| action.receiverId, | ||
| action.signerId, | ||
| "donate", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe change to "direct" for clarity
indexer.ts
Outdated
| }; | ||
| await context.db.Donation.insert(donation); | ||
|
|
||
| if (actionName != "donate") { // update pot data such as public donations and matchingpool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to actionName == "pot" for clarity?
indexer.ts
Outdated
| registrant_id: data._project_id || signerId, | ||
| status: registry.default_registration_status, | ||
| submitted_at: new Date( | ||
| Number(BigInt(block.header().timestampNanosec) / BigInt(1000000)) | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could get these from function result (ProjectExternal) if desired
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but except there is a chance these data source might be incorrect, i wanted to use them since they're readily available as decoding function results take extra steps including looping through receipts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the thing is also that if it is registered by admin, it will be approved by default (at least that is the current functionality). i think it's probably better to take it from the decoded SuccessValue
Also as I noted elsewhere this morning, since the new Lists contract will be up very soon (ideally by EOD today) and existing Potlock registrations will be migrated to this contract via its register method, let's not worry about indexing the legacy Registry contract
| timestamp: reg.submitted_at, | ||
| type: "Register", | ||
| action_result: reg.registrant_id, | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use tx hash instead of receipt hash
indexer.ts
Outdated
| let data = JSON.parse(args); | ||
| console.log("new Project data::", { ...data }, receiverId); | ||
| let registry = (await context.db.List.select({ id: receiverId }))[0]; // fetch the registry so as to get default | ||
| let reg = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reg also needs a list_id (registry.id)
| ); | ||
|
|
||
| CREATE TABLE | ||
| list_registration ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also needs list_id
indexer.ts
Outdated
| receiptId | ||
| ) { | ||
| let data = JSON.parse(args); | ||
| console.log("new factory data::", { ...data }, receiverId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might want to update this log text
| reviewer_id: signerId, | ||
| notes: update_data.notes, | ||
| status: update_data.status, | ||
| reviewed_at: update_data.updated_at, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated_at won't be present on update_data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ermm... it won't? the chef_set_application_status function returns an application object with those values... including updated at
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it appears that you are using the function call args, not the result
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was using the result, let update_data = JSON.parse(atob(receipt.status["SuccessValue"]));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oooooops sorry missed that
| }; | ||
| let applicationUpdate = { | ||
| current_status: update_data.status, | ||
| last_updated_at: update_data.updated_at, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto..... 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
........ditto 😶🌫️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
........ ditto!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you win
indexer.ts
Outdated
| default_registration_status: data.status, | ||
| }; | ||
|
|
||
| await context.db.List.update({ id: receiverId }, listUpdate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this works for the current registry contract but not for Lists contract, where the list_id will be specified in the call. changing to id: data.list_id || receiverId should resolve
| console.log("set payout data::", { ...data }, receiverId); | ||
| let payouts = data.payouts; | ||
| for (const payout in payouts) { | ||
| // general question: should we register projects as accounts? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
indexer.ts
Outdated
| let potPayout = { | ||
| recipient_id: payout["project_id"], | ||
| amount: payout["amount"], | ||
| ft_id: payout["ft_id"] || null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to payout["ft_id"] || "near"
| recipient_id: payout["project_id"], | ||
| amount: payout["amount"], | ||
| ft_id: payout["ft_id"] || null, | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use tx hash instead of receipt hash
| let created_at = new Date( | ||
| Number(BigInt(block.header().timestampNanosec) / BigInt(1000000)) // convert to ms then date | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this calculation is done a lot, perhaps worth doing once for the block further up the chain and passing down?
| pot_id: receiverId, | ||
| created_at, | ||
| message: data.reason, | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use tx hash instead of receipt hash
indexer.ts
Outdated
| receiver_id: receiverId, | ||
| timestamp: created_at, | ||
| type: "Challenge_Payout", | ||
| action_result: receiverId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure this is useful
| timestamp: created_at, | ||
| type: "Challenge_Payout", | ||
| action_result: receiverId, | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use tx hash instead of receipt hash
| let payout = { | ||
| recipient_id: data.project_id, | ||
| amount: data.amount, | ||
| paid_at: data.paid_at, | ||
| tx_hash: receiptId, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't the args (data) will be in this format you're expecting here. the transfer_payout_callback method receives a payout argument so you may have to inspect this to get project_id, amount etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the data is the payout argument....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but won't it be at data.payout?
| recipient_id: data.project_id, | ||
| amount: data.amount, | ||
| paid_at: data.paid_at, | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to tx hash instead of receipt hash
| } | ||
| } | ||
|
|
||
| async function handlePayout(args, receiverId, signerId, receiptId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when is pot.all_paid_out updated?
indexer.ts
Outdated
| break; | ||
| case "owner_remove_admins": | ||
| console.log( | ||
| "setting payot....:", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
incorrect log
| action.receiptId | ||
| ); | ||
| break; | ||
| case "owner_remove_admins": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI there is a method with this name on all the contracts, so will need to be more specific to handle this based on the contract (registry/lists, pot factory, pot, donation)
indexer.ts
Outdated
| let ts = new Date( | ||
| Number(BigInt(block.header().timestampNanosec) / BigInt(1000000)) // convert to ms then date | ||
| ) | ||
| let list = await context.db.List.select({id: receiverId}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to id: data.list_id || receiverId to handle lists contract also
| owner_id: data.owner, | ||
| default_registration_status: "Approved", // the first registry contract has approved as default, and the later changed through the admin set function call, which we also listen to, so it should self correct. | ||
| name: receiverId.split(".")[0], | ||
| tx_hash: receiptId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use tx hash not receipt hash
No description provided.