Skip to content

Commit 7e69b41

Browse files
committed
receipts: FetchReceipt
1 parent 9708f4a commit 7e69b41

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

receipts/fetch.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package receipts
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"math/big"
7+
8+
"github.com/0xsequence/ethkit/ethrpc"
9+
"github.com/0xsequence/ethkit/go-ethereum"
10+
"github.com/0xsequence/ethkit/go-ethereum/common"
11+
"github.com/0xsequence/ethkit/go-ethereum/core/types"
12+
sequence "github.com/0xsequence/go-sequence"
13+
)
14+
15+
// FetchReceipt looks up the transaction that emitted Call* events for the given
16+
// digest and returns the native receipt alongside all decoded Sequence receipts
17+
// for that digest.
18+
func FetchReceipt(ctx context.Context, digest common.Hash, provider *ethrpc.Provider, fromBlock, toBlock *big.Int) (*types.Receipt, Receipts, error) {
19+
if provider == nil {
20+
return nil, Receipts{}, fmt.Errorf("no provider")
21+
}
22+
23+
query := ethereum.FilterQuery{
24+
FromBlock: fromBlock,
25+
ToBlock: toBlock,
26+
Topics: [][]common.Hash{
27+
{sequence.V3CallSucceeded, sequence.V3CallFailed, sequence.V3CallAborted, sequence.V3CallSkipped},
28+
{digest},
29+
},
30+
}
31+
32+
logs, err := provider.FilterLogs(ctx, query)
33+
if err != nil {
34+
return nil, Receipts{}, fmt.Errorf("unable to filter logs: %w", err)
35+
}
36+
if len(logs) == 0 {
37+
// Fallback for legacy events where the digest is not indexed.
38+
query.Topics = [][]common.Hash{{sequence.V3CallSucceeded, sequence.V3CallFailed, sequence.V3CallAborted, sequence.V3CallSkipped}}
39+
logs, err = provider.FilterLogs(ctx, query)
40+
if err != nil {
41+
return nil, Receipts{}, fmt.Errorf("unable to filter logs without digest topic: %w", err)
42+
}
43+
}
44+
45+
log, err := findDigestLog(logs, digest)
46+
if err != nil {
47+
return nil, Receipts{}, err
48+
}
49+
50+
receipt, err := provider.TransactionReceipt(ctx, log.TxHash)
51+
if err != nil {
52+
return nil, Receipts{}, fmt.Errorf("unable to get transaction receipt %v: %w", log.TxHash, err)
53+
}
54+
55+
decoded, err := TransactionReceiptsForReceipt(ctx, receipt, provider)
56+
if err != nil {
57+
return receipt, Receipts{}, fmt.Errorf("unable to decode transaction receipt %v: %w", receipt.TxHash, err)
58+
}
59+
60+
receipts := decoded.Find(digest)
61+
if receipts == nil {
62+
return receipt, Receipts{}, fmt.Errorf("decoded receipts do not include digest %v", digest)
63+
}
64+
65+
return receipt, *receipts, nil
66+
}
67+
68+
func findDigestLog(logs []types.Log, digest common.Hash) (*types.Log, error) {
69+
var selected *types.Log
70+
71+
for i := range logs {
72+
log := &logs[i]
73+
74+
if !matchesDigest(log, digest) {
75+
continue
76+
}
77+
78+
if selected == nil || isNewerLog(log, selected) {
79+
selected = log
80+
}
81+
}
82+
83+
if selected == nil {
84+
return nil, fmt.Errorf("no Call* events found for digest %v", digest)
85+
}
86+
87+
return selected, nil
88+
}
89+
90+
func matchesDigest(log *types.Log, digest common.Hash) bool {
91+
if hash, _, err := sequence.V3DecodeCallSucceededEvent(log); err == nil && hash == digest {
92+
return true
93+
}
94+
if hash, _, _, err := sequence.V3DecodeCallFailedEvent(log); err == nil && hash == digest {
95+
return true
96+
}
97+
if hash, _, _, err := sequence.V3DecodeCallAbortedEvent(log); err == nil && hash == digest {
98+
return true
99+
}
100+
if hash, _, err := sequence.V3DecodeCallSkippedEvent(log); err == nil && hash == digest {
101+
return true
102+
}
103+
return false
104+
}
105+
106+
func isNewerLog(a, b *types.Log) bool {
107+
if a.BlockNumber != b.BlockNumber {
108+
return a.BlockNumber > b.BlockNumber
109+
}
110+
if a.TxIndex != b.TxIndex {
111+
return a.TxIndex > b.TxIndex
112+
}
113+
return a.Index > b.Index
114+
}

0 commit comments

Comments
 (0)