diff --git a/pkg/parser/bebop/bebop_test.go b/pkg/parser/bebop/bebop_test.go index b1b7e80..427b67d 100644 --- a/pkg/parser/bebop/bebop_test.go +++ b/pkg/parser/bebop/bebop_test.go @@ -115,3 +115,26 @@ func TestParseSingleOrderEvent(t *testing.T) { t.Log(log.TakerToken) t.Log(log.TakerTokenAmount) } + +func TestParseSwapSingleFromContract(t *testing.T) { + t.Skip("Need to add the rpc url that enables the trace call JSON-RPC") + eventRaw := `{"address":"0xbbbbbbb520d69a9775e85b458c58c648259fad5f","topics":["0xadd7095becdaa725f0f33243630938c861b0bba83dfd217d4055701aa768ec2e","0x0000000000000000000000000000000000000000000000000000000000000000"],"data":"0x","blockNumber":"0x13e7401","transactionHash":"0x4b15bfb1024c71eb76a48dbf1d0faea77044433807e2052dbb3a00b3ee054a14","transactionIndex":"0x3f","blockHash":"0x4161ffa4596f3bd812959e7a91038a26d27f57aa51d9ef3ee4cd0772d11c86fe","logIndex":"0x176","removed":false}` + events := types.Log{} + err := json.Unmarshal([]byte(eventRaw), &events) + require.NoError(t, err) + ethClient, err := ethclient.Dial(rpcURL) + if err != nil { + panic(err) + } + traceCalls := tracecall.NewCache(rpcnode.NewClient(zap.S(), ethClient)) + p := MustNewParser(traceCalls) + log, err := p.Parse(events, uint64(time.Now().Unix())) + require.NoError(t, err) + require.Equal(t, log.EventHash, p.eventHash) + t.Log(log.Maker) + t.Log(log.MakerToken) + t.Log(log.MakerTokenAmount) + t.Log(log.Taker) + t.Log(log.TakerToken) + t.Log(log.TakerTokenAmount) +} diff --git a/pkg/parser/bebop/parser.go b/pkg/parser/bebop/parser.go index c4af956..a205223 100644 --- a/pkg/parser/bebop/parser.go +++ b/pkg/parser/bebop/parser.go @@ -23,6 +23,9 @@ import ( const ( TradeEvent = "BebopOrder" OrderParam = "order" + + balanceOfMethodID = "0x70a08231" + swapSingleFromContractFunctionName = "swapSingleFromContract" ) var ( @@ -206,7 +209,7 @@ func (p *Parser) ParseFromInternalCall(order storage.TradeLog, internalCall type } break } - if filledTakerAmount == nil { + if filledTakerAmount == nil && contractCall.Name != swapSingleFromContractFunctionName { return order, ErrParamNotFound } for _, param := range contractCall.Params { @@ -215,7 +218,7 @@ func (p *Parser) ParseFromInternalCall(order storage.TradeLog, internalCall type } switch { case p.singleOrderFunc.Has(contractCall.Name): - return p.parseSingleSwap(order, contractCall, param, filledTakerAmount) + return p.parseSingleSwap(order, contractCall, param, filledTakerAmount, internalCall) case p.multiOrderFunc.Has(contractCall.Name): return p.parseMultiSwap(order, contractCall, param, filledTakerAmount) case p.aggregateOrderFunc.Has(contractCall.Name): @@ -281,10 +284,34 @@ func (p *Parser) LogFromExchange(log ethereumTypes.Log) bool { strings.EqualFold(log.Topics[0].String(), p.eventHash) } +func (p *Parser) getFilledTakerAmount(order SingleOrder, traceCall types.CallFrame) *big.Int { + for _, call := range traceCall.Calls { + if call.From != strings.ToLower(p.Address()) { + continue + } + if call.To != order.TakerToken { + continue + } + if !strings.HasPrefix(call.Input, balanceOfMethodID) { + continue + } + if len(call.Output) <= 2 { + continue + } + balance, ok := new(big.Int).SetString(call.Output[2:], 16) + if !ok { + continue + } + return balance + } + return nil +} + func (p *Parser) parseSingleSwap(order storage.TradeLog, contractCall *tradingTypes.ContractCall, orderParam tradingTypes.ContractCallParam, - fillTakerAmount *big.Int) (storage.TradeLog, error) { + fillTakerAmount *big.Int, + internalCall types.CallFrame) (storage.TradeLog, error) { var rfqOrder SingleOrder if err := unpackOrder(orderParam.Value, &rfqOrder); err != nil { return order, err @@ -301,6 +328,13 @@ func (p *Parser) parseSingleSwap(order storage.TradeLog, break } + if contractCall.Name == swapSingleFromContractFunctionName { + fillTakerAmount = p.getFilledTakerAmount(rfqOrder, internalCall) + if fillTakerAmount == nil { + return order, ErrParamNotFound + } + } + if fillTakerAmount.Cmp(big.NewInt(0)) > 0 && fillTakerAmount.Cmp(rfqOrder.TakerAmount) < 0 { tmp := big.NewInt(0).Mul(rfqOrder.MakerAmount, fillTakerAmount) rfqOrder.MakerAmount = tmp.Div(tmp, rfqOrder.TakerAmount)