-
Notifications
You must be signed in to change notification settings - Fork 8
/
receipt_fetcher.go
137 lines (116 loc) · 3.53 KB
/
receipt_fetcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package sequence
import (
"context"
"time"
"github.com/0xsequence/ethkit"
"github.com/0xsequence/ethkit/ethreceipts"
"github.com/0xsequence/ethkit/go-ethereum/common"
"github.com/0xsequence/ethkit/go-ethereum/core/types"
)
type MetaTxnResult struct {
MetaTxnID MetaTxnID
Status MetaTxnStatus
Reason string
}
func FetchMetaTransactionReceipt(ctx context.Context, receiptListener *ethreceipts.ReceiptsListener, metaTxnID MetaTxnID, optTimeout ...time.Duration) (*MetaTxnResult, *ethreceipts.Receipt, ethreceipts.WaitReceiptFinalityFunc, error) {
// Use optional timeout if passed, otherwise use deadline on the provided ctx, or finally,
// set a default timeout of 200 seconds.
var cancel context.CancelFunc
if len(optTimeout) > 0 {
ctx, cancel = context.WithTimeout(ctx, optTimeout[0])
defer cancel()
} else {
if _, ok := ctx.Deadline(); !ok {
ctx, cancel = context.WithTimeout(ctx, 200*time.Second)
defer cancel()
}
}
var result *MetaTxnResult
metaTxnHash := common.HexToHash(string(metaTxnID))
receipt, waitFinality, err := receiptListener.FetchTransactionReceiptWithFilter(ctx, FilterMetaTransactionID(metaTxnHash).LimitOne(true).SearchCache(true))
if err != nil {
return nil, nil, nil, err
}
result = &MetaTxnResult{
MetaTxnID: metaTxnID,
}
var isV2 bool
for _, log := range receipt.Logs() {
isTxExecutedV1 := V1IsTxExecutedEvent(log, metaTxnHash)
isTxFailedV1 := V1IsTxFailedEvent(log, metaTxnHash)
isTxExecutedV2 := IsTxExecutedEvent(log, metaTxnHash)
isTxFailedV2 := V2IsTxFailedEvent(log, metaTxnHash)
if isTxExecutedV1 || isTxFailedV1 {
isV2 = false
break
} else if isTxExecutedV2 || isTxFailedV2 {
isV2 = true
break
}
}
for _, log := range receipt.Logs() {
var isTxExecuted, isTxFailed bool
var reason string
if isV2 {
isTxExecuted = IsTxExecutedEvent(log, metaTxnHash)
isTxFailed = V2IsTxFailedEvent(log, metaTxnHash)
if isTxFailed {
_, reason, _, _ = V2DecodeTxFailedEvent(log)
}
} else {
isTxExecuted = V1IsTxExecutedEvent(log, metaTxnHash)
isTxFailed = V1IsTxFailedEvent(log, metaTxnHash)
if isTxFailed {
_, reason, _ = V1DecodeTxFailedEvent(log)
}
}
if isTxExecuted {
result.Status = MetaTxnExecuted
break
} else if isTxFailed {
result.Status = MetaTxnFailed
result.Reason = reason
}
}
return result, receipt, waitFinality, nil
}
func FilterMetaTransactionID(metaTxnID ethkit.Hash) ethreceipts.FilterQuery {
return ethreceipts.FilterLogs(func(logs []*types.Log) bool {
for _, log := range logs {
isTxExecutedV1 := V1IsTxExecutedEvent(log, metaTxnID)
isTxFailedV1 := V1IsTxFailedEvent(log, metaTxnID)
isTxExecutedV2 := IsTxExecutedEvent(log, metaTxnID)
isTxFailedV2 := V2IsTxFailedEvent(log, metaTxnID)
if isTxExecutedV1 || isTxFailedV1 || isTxExecutedV2 || isTxFailedV2 {
// found the sequence meta txn
return true
}
}
return false
})
}
// Find any Sequence meta txns
func FilterMetaTransactionAny() ethreceipts.FilterQuery {
return ethreceipts.FilterLogs(func(logs []*types.Log) bool {
foundNonceEvent := false
for _, log := range logs {
if len(log.Topics) > 0 && log.Topics[0] == NonceChangeEventSig {
foundNonceEvent = true
break
}
}
if !foundNonceEvent {
return false
}
for _, log := range logs {
if len(log.Topics) == 1 && log.Topics[0] == V1TxFailedEventSig {
// failed sequence txn
return true
} else if len(log.Topics) == 0 && len(log.Data) == 32 {
// possibly a successful sequence txn -- but not for certain
return true
}
}
return false
})
}