Skip to content

Commit 7c01211

Browse files
committed
Working but a bit ugly
1 parent 8ee2774 commit 7c01211

File tree

3 files changed

+364
-328
lines changed

3 files changed

+364
-328
lines changed
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
package ledger1
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
8+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
9+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors"
10+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/ledger10"
11+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
12+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/normalize"
13+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
14+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/topics"
15+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
16+
)
17+
18+
func (r *Reconciler1) GetStatements1(pos *types.AppPosition, trans *types.Transaction) ([]types.Statement, error) {
19+
results := make([]types.Statement, 0, 20)
20+
if ledger10.AssetOfInterest(r.opts.AssetFilters, base.FAKE_ETH_ADDRESS) {
21+
s := types.Statement{
22+
AccountedFor: r.opts.AccountFor,
23+
Sender: trans.From,
24+
Recipient: trans.To,
25+
BlockNumber: trans.BlockNumber,
26+
TransactionIndex: trans.TransactionIndex,
27+
TransactionHash: trans.Hash,
28+
LogIndex: 0,
29+
Timestamp: trans.Timestamp,
30+
Asset: base.FAKE_ETH_ADDRESS,
31+
Symbol: "WEI",
32+
Decimals: 18,
33+
SpotPrice: 0.0,
34+
PriceSource: "not-priced",
35+
}
36+
if r.opts.AsEther {
37+
s.Symbol = "ETH"
38+
}
39+
if trans.To.IsZero() && trans.Receipt != nil && !trans.Receipt.ContractAddress.IsZero() {
40+
s.Recipient = trans.Receipt.ContractAddress
41+
}
42+
43+
reconciled := false
44+
if !r.opts.UseTraces {
45+
if s.Sender == r.opts.AccountFor {
46+
gasUsed := new(base.Wei)
47+
if trans.Receipt != nil {
48+
gasUsed.SetUint64(uint64(trans.Receipt.GasUsed))
49+
}
50+
gasPrice := new(base.Wei).SetUint64(uint64(trans.GasPrice))
51+
gasOut := new(base.Wei).Mul(gasUsed, gasPrice)
52+
s.AmountOut = trans.Value
53+
s.GasOut = *gasOut
54+
}
55+
56+
if s.Recipient == r.opts.AccountFor {
57+
if s.BlockNumber == 0 {
58+
s.PrefundIn = trans.Value
59+
} else {
60+
if trans.Rewards != nil {
61+
s.MinerBaseRewardIn = trans.Rewards.Block
62+
s.MinerNephewRewardIn = trans.Rewards.Nephew
63+
s.MinerTxFeeIn = trans.Rewards.TxFee
64+
s.MinerUncleRewardIn = trans.Rewards.Uncle
65+
} else {
66+
s.AmountIn = trans.Value
67+
}
68+
}
69+
}
70+
71+
var err error
72+
if s.PrevBal, s.BegBal, s.EndBal, err = r.opts.Connection.GetReconBalances(&rpc.BalanceOptions{
73+
PrevAppBlk: pos.Prev,
74+
CurrBlk: trans.BlockNumber,
75+
Asset: s.Asset,
76+
Holder: s.AccountedFor,
77+
}); err != nil {
78+
return nil, err
79+
}
80+
reconciled = r.trialBalance(pos, trans, &s)
81+
if reconciled && s.IsMaterial() {
82+
results = append(results, s)
83+
}
84+
}
85+
86+
if r.opts.UseTraces || !reconciled {
87+
results = make([]types.Statement, 0, 20) /* reset this */
88+
if s, err := r.getStatementFromTraces(pos, trans, &s); err != nil {
89+
logger.Warn(colors.Yellow+"Statement at ", fmt.Sprintf("%d.%d", trans.BlockNumber, trans.TransactionIndex), " does not reconcile."+colors.Off)
90+
} else {
91+
var err error
92+
if s.PrevBal, s.BegBal, s.EndBal, err = r.opts.Connection.GetReconBalances(&rpc.BalanceOptions{
93+
PrevAppBlk: pos.Prev,
94+
CurrBlk: trans.BlockNumber,
95+
Asset: s.Asset,
96+
Holder: s.AccountedFor,
97+
}); err != nil {
98+
return nil, err
99+
}
100+
_ = r.trialBalance(pos, trans, s)
101+
results = append(results, *s)
102+
}
103+
}
104+
}
105+
106+
if trans.Receipt != nil {
107+
if statements, err := r.getStatementsFromLogs(trans.Receipt.Logs); err != nil {
108+
return nil, err
109+
} else {
110+
receiptStatements := make([]types.Statement, 0, len(statements))
111+
for _, s := range statements {
112+
var err error
113+
if s.PrevBal, s.BegBal, s.EndBal, err = r.opts.Connection.GetReconBalances(&rpc.BalanceOptions{
114+
PrevAppBlk: pos.Prev,
115+
CurrBlk: trans.BlockNumber,
116+
Asset: s.Asset,
117+
Holder: s.AccountedFor,
118+
}); err != nil {
119+
return nil, err
120+
}
121+
reconciled := r.trialBalance(pos, trans, &s)
122+
123+
if reconciled {
124+
id := fmt.Sprintf(" %d.%d.%d", s.BlockNumber, s.TransactionIndex, s.LogIndex)
125+
logger.Progress(true, colors.Green+"Transaction", id, "reconciled "+colors.Off)
126+
} else {
127+
if os.Getenv("TEST_MODE") != "true" {
128+
id := fmt.Sprintf(" %d.%d.%d", s.BlockNumber, s.TransactionIndex, s.LogIndex)
129+
logger.Warn("Log statement at ", id, " does not reconcile.")
130+
}
131+
}
132+
133+
// order matters
134+
if s.IsMaterial() {
135+
receiptStatements = append(receiptStatements, s)
136+
}
137+
}
138+
results = append(results, receiptStatements...)
139+
}
140+
}
141+
142+
return results, nil
143+
}
144+
145+
func (r *Reconciler1) getStatementFromTraces(pos *types.AppPosition, trans *types.Transaction, s *types.Statement) (*types.Statement, error) {
146+
147+
ret := *s
148+
// clear all the internal accounting values. Keeps AmountIn, AmountOut and GasOut because
149+
// those are at the top level (both the transaction itself and trace '0' have them). We
150+
// skip trace '0' because it's the same as the transaction.
151+
// ret.AmountIn.SetUint64(0)
152+
ret.InternalIn.SetUint64(0)
153+
ret.MinerBaseRewardIn.SetUint64(0)
154+
ret.MinerNephewRewardIn.SetUint64(0)
155+
ret.MinerTxFeeIn.SetUint64(0)
156+
ret.MinerUncleRewardIn.SetUint64(0)
157+
ret.CorrectingIn.SetUint64(0)
158+
ret.PrefundIn.SetUint64(0)
159+
ret.SelfDestructIn.SetUint64(0)
160+
161+
// ret.AmountOut.SetUint64(0)
162+
// ret.GasOut.SetUint64(0)
163+
ret.InternalOut.SetUint64(0)
164+
ret.CorrectingOut.SetUint64(0)
165+
ret.SelfDestructOut.SetUint64(0)
166+
167+
if traces, err := r.opts.Connection.GetTracesByTransactionHash(trans.Hash.Hex(), trans); err != nil {
168+
return nil, err
169+
170+
} else {
171+
// These values accumulate...so we use += instead of =
172+
for i, trace := range traces {
173+
if i == 0 {
174+
// the first trace is identical to the transaction itself, so we can skip it
175+
continue
176+
}
177+
178+
if trace.Action.CallType == "delegatecall" && trace.Action.To != s.AccountedFor {
179+
// delegate calls are not included in the transaction's gas cost, so we skip them
180+
continue
181+
}
182+
183+
plusEq := func(a1, a2 *base.Wei) base.Wei {
184+
return *a1.Add(a1, a2)
185+
}
186+
187+
// Do not collapse, more than one of these can be true at the same time
188+
if trace.Action.From == s.AccountedFor {
189+
ret.InternalOut = plusEq(&ret.InternalOut, &trace.Action.Value)
190+
ret.Sender = trace.Action.From
191+
if trace.Action.To.IsZero() {
192+
if trace.Result != nil {
193+
ret.Recipient = trace.Result.Address
194+
}
195+
} else {
196+
ret.Recipient = trace.Action.To
197+
}
198+
}
199+
200+
if trace.Action.To == s.AccountedFor {
201+
ret.InternalIn = plusEq(&ret.InternalIn, &trace.Action.Value)
202+
ret.Sender = trace.Action.From
203+
ret.Recipient = trace.Action.To
204+
}
205+
206+
if trace.Action.SelfDestructed == s.AccountedFor {
207+
ret.SelfDestructOut = plusEq(&ret.SelfDestructOut, &trace.Action.Balance)
208+
ret.Sender = trace.Action.SelfDestructed
209+
if ret.Sender.IsZero() {
210+
ret.Sender = trace.Action.Address
211+
}
212+
ret.Recipient = trace.Action.RefundAddress
213+
}
214+
215+
if trace.Action.RefundAddress == s.AccountedFor {
216+
ret.SelfDestructIn = plusEq(&ret.SelfDestructIn, &trace.Action.Balance)
217+
ret.Sender = trace.Action.SelfDestructed
218+
if ret.Sender.IsZero() {
219+
ret.Sender = trace.Action.Address
220+
}
221+
ret.Recipient = trace.Action.RefundAddress
222+
}
223+
224+
if trace.Action.Address == s.AccountedFor && !trace.Action.RefundAddress.IsZero() {
225+
ret.SelfDestructOut = plusEq(&ret.SelfDestructOut, &trace.Action.Balance)
226+
// self destructed send
227+
ret.Sender = trace.Action.Address
228+
ret.Recipient = trace.Action.RefundAddress
229+
}
230+
231+
if trace.Result != nil {
232+
if trace.Result.Address == s.AccountedFor {
233+
ret.InternalIn = plusEq(&ret.InternalIn, &trace.Action.Value)
234+
ret.Sender = trace.Action.From
235+
ret.Recipient = trace.Result.Address
236+
}
237+
}
238+
}
239+
}
240+
241+
return &ret, nil
242+
}
243+
244+
func (r *Reconciler1) getStatementsFromLogs(logs []types.Log) ([]types.Statement, error) {
245+
receiptStatements := make([]types.Statement, 0, 20)
246+
for _, log := range logs {
247+
if log.Topics[0] != topics.TransferTopic {
248+
continue
249+
}
250+
addrArray := []base.Address{r.opts.AccountFor}
251+
if r.opts.AppFilters.ApplyLogFilter(&log, addrArray) && ledger10.AssetOfInterest(r.opts.AssetFilters, log.Address) {
252+
normalized, err := normalize.NormalizeKnownLogs(&log)
253+
if err != nil {
254+
continue
255+
} else if normalized.IsNFT() {
256+
continue
257+
} else {
258+
sender := base.HexToAddress(normalized.Topics[1].Hex())
259+
recipient := base.HexToAddress(normalized.Topics[2].Hex())
260+
isSender, isRecipient := r.opts.AccountFor == sender, r.opts.AccountFor == recipient
261+
if !isSender && !isRecipient {
262+
continue
263+
}
264+
265+
sym := normalized.Address.DefaultSymbol()
266+
decimals := base.Value(18)
267+
name := r.names[normalized.Address]
268+
if name.Address == normalized.Address {
269+
if name.Symbol != "" {
270+
sym = name.Symbol
271+
}
272+
if name.Decimals != 0 {
273+
decimals = base.Value(name.Decimals)
274+
}
275+
}
276+
277+
var amountIn, amountOut base.Wei
278+
amount, _ := new(base.Wei).SetString(strings.ReplaceAll(normalized.Data, "0x", ""), 16)
279+
if amount == nil {
280+
amount = base.NewWei(0)
281+
}
282+
if r.opts.AccountFor == sender {
283+
amountOut = *amount
284+
}
285+
if r.opts.AccountFor == recipient {
286+
amountIn = *amount
287+
}
288+
s := types.Statement{
289+
AccountedFor: r.opts.AccountFor,
290+
Sender: sender,
291+
Recipient: recipient,
292+
BlockNumber: normalized.BlockNumber,
293+
TransactionIndex: normalized.TransactionIndex,
294+
LogIndex: normalized.LogIndex,
295+
TransactionHash: normalized.TransactionHash,
296+
Timestamp: normalized.Timestamp,
297+
Asset: normalized.Address,
298+
Symbol: sym,
299+
Decimals: decimals,
300+
SpotPrice: 0.0,
301+
PriceSource: "not-priced",
302+
AmountIn: amountIn,
303+
AmountOut: amountOut,
304+
}
305+
receiptStatements = append(receiptStatements, s)
306+
}
307+
}
308+
}
309+
return receiptStatements, nil
310+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package ledger1
2+
3+
import (
4+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/ledger2"
5+
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
6+
)
7+
8+
// GetTransfers1 returns a statement from a given transaction
9+
func (r *Reconciler1) GetTransfers1(pos *types.AppPosition, trans *types.Transaction) ([]types.Transfer, error) {
10+
// statements := make([]types.Statement, 0, 20)
11+
// if !r.opts.UseTraces {
12+
// stmt := r.getStatementFromTransaction(trans)
13+
// statements = append(statements, *stmt)
14+
// } else {
15+
// if stmt, err := r.getStatementFromTraces(trans); err == nil {
16+
// statements = append(statements, *stmt)
17+
// }
18+
// }
19+
// if trans.Receipt != nil {
20+
// for _, log := range trans.Receipt.Logs {
21+
// if stmt, err := r.getStatementFromLog(&log); err != nil {
22+
// return nil, err
23+
// } else if stmt == nil {
24+
// continue
25+
// } else {
26+
// statements = append(statements, *stmt)
27+
// }
28+
// }
29+
// }
30+
// return convertToTransfers(statements)
31+
r2 := ledger2.NewReconciler(r.opts)
32+
if statements, err := r2.GetStatements2(pos, trans); err != nil {
33+
return nil, err
34+
} else {
35+
return convertToTransfers(statements)
36+
}
37+
}
38+
39+
func convertToTransfers(statements []types.Statement) ([]types.Transfer, error) {
40+
transfers := make([]types.Transfer, 0, len(statements)*2)
41+
for _, stmnt := range statements {
42+
t := types.Transfer{
43+
Asset: stmnt.Asset,
44+
Holder: stmnt.AccountedFor,
45+
Amount: *stmnt.AmountNet(),
46+
BlockNumber: stmnt.BlockNumber,
47+
TransactionIndex: stmnt.TransactionIndex,
48+
LogIndex: stmnt.LogIndex,
49+
Decimals: stmnt.Decimals,
50+
}
51+
transfers = append(transfers, t)
52+
}
53+
return transfers, nil
54+
}

0 commit comments

Comments
 (0)