Skip to content

Commit 998911e

Browse files
committed
receipts: FetchReceipt
1 parent 9708f4a commit 998911e

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

receipts/fetch.go

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

0 commit comments

Comments
 (0)