From d20cda077de2af3ca416c1626b0c7e6e958c3e5b Mon Sep 17 00:00:00 2001 From: minhthanh Date: Thu, 25 Apr 2024 17:12:11 +0700 Subject: [PATCH] add uniswapx (#42) * add uniswapx * update to uniswapx v2 * handle error create type --- cmd/tradelogs/main.go | 2 + internal/worker/worker.go | 5 +- pkg/evmlistenerclient/client.go | 1 + pkg/parser/hashflow/parser.go | 4 + pkg/parser/hashflow_v3/parser.go | 4 + pkg/parser/kyberswap/parser.go | 4 + pkg/parser/kyberswap_rfq/parser.go | 4 + pkg/parser/native/parser.go | 4 + pkg/parser/oneinch/parser.go | 4 + pkg/parser/oneinchv6/parser.go | 4 + pkg/parser/paraswap/parser.go | 4 + pkg/parser/parser.go | 1 + pkg/parser/tokenlon/parser.go | 4 + pkg/parser/uniswapx/abi.json | 1 + pkg/parser/uniswapx/gen.sh | 1 + pkg/parser/uniswapx/parser.go | 308 ++++++++++ pkg/parser/uniswapx/uniswap_test.go | 71 +++ pkg/parser/uniswapx/uniswapx.go | 878 ++++++++++++++++++++++++++++ pkg/parser/zxotc/parser.go | 4 + pkg/parser/zxrfq/parser.go | 4 + pkg/storage/storage.go | 18 + 21 files changed, 1328 insertions(+), 2 deletions(-) create mode 100644 pkg/parser/uniswapx/abi.json create mode 100755 pkg/parser/uniswapx/gen.sh create mode 100644 pkg/parser/uniswapx/parser.go create mode 100644 pkg/parser/uniswapx/uniswap_test.go create mode 100644 pkg/parser/uniswapx/uniswapx.go diff --git a/cmd/tradelogs/main.go b/cmd/tradelogs/main.go index f74484f..52659ac 100644 --- a/cmd/tradelogs/main.go +++ b/cmd/tradelogs/main.go @@ -12,6 +12,7 @@ import ( "github.com/KyberNetwork/tradelogs/pkg/parser" "github.com/KyberNetwork/tradelogs/pkg/parser/oneinch" "github.com/KyberNetwork/tradelogs/pkg/parser/oneinchv6" + "github.com/KyberNetwork/tradelogs/pkg/parser/uniswapx" "github.com/KyberNetwork/tradelogs/pkg/rpcnode" "github.com/KyberNetwork/tradelogs/pkg/tracecall" @@ -105,6 +106,7 @@ func run(c *cli.Context) error { hashflowv3.MustNewParser(), oneinch.MustNewParser(traceCalls), oneinchv6.MustNewParser(traceCalls), + uniswapx.MustNewParser(traceCalls), } tradeLogChan := make(chan storage.TradeLog, 1000) diff --git a/internal/worker/worker.go b/internal/worker/worker.go index 45a9ff1..b177b9d 100644 --- a/internal/worker/worker.go +++ b/internal/worker/worker.go @@ -39,7 +39,8 @@ func New(l *zap.SugaredLogger, s *storage.Storage, listener *evmlistenerclient.C } func (w *Worker) Run(ctx context.Context) error { - retryTimer := time.NewTicker(evmlistenerclient.BlockTime) + retryTimer := time.NewTicker(evmlistenerclient.RetryTime) + defer retryTimer.Stop() for { select { case <-retryTimer.C: @@ -127,7 +128,7 @@ func (w *Worker) processMessages(m []evmlistenerclient.Message) error { func (w *Worker) retryParseLog() error { insertOrders := []storage.TradeLog{} - logs, err := w.s.GetErrorLogs() + logs, err := w.s.GetErrorLogsSince(time.Now().Add(-time.Hour * 24).Unix()) if err != nil { return err } diff --git a/pkg/evmlistenerclient/client.go b/pkg/evmlistenerclient/client.go index b273100..68f5402 100644 --- a/pkg/evmlistenerclient/client.go +++ b/pkg/evmlistenerclient/client.go @@ -17,6 +17,7 @@ const ( var ( BlockTime = 12 * time.Second + RetryTime = 2 * time.Second ) type Config struct { diff --git a/pkg/parser/hashflow/parser.go b/pkg/parser/hashflow/parser.go index 37b1e12..7f94762 100644 --- a/pkg/parser/hashflow/parser.go +++ b/pkg/parser/hashflow/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExHashflow } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/hashflow_v3/parser.go b/pkg/parser/hashflow_v3/parser.go index fb3f7a0..6a790bc 100644 --- a/pkg/parser/hashflow_v3/parser.go +++ b/pkg/parser/hashflow_v3/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExHashflowV3 } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/kyberswap/parser.go b/pkg/parser/kyberswap/parser.go index 2b6fb0e..0871c7a 100644 --- a/pkg/parser/kyberswap/parser.go +++ b/pkg/parser/kyberswap/parser.go @@ -76,3 +76,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExKs } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/kyberswap_rfq/parser.go b/pkg/parser/kyberswap_rfq/parser.go index fef3ded..a024384 100644 --- a/pkg/parser/kyberswap_rfq/parser.go +++ b/pkg/parser/kyberswap_rfq/parser.go @@ -79,3 +79,7 @@ func (p *Parser) Exchange() string { return parser.ExKsRFQ } +func (p *Parser) UseTraceCall() bool { + return false +} + diff --git a/pkg/parser/native/parser.go b/pkg/parser/native/parser.go index 1b7a35c..2902ce3 100644 --- a/pkg/parser/native/parser.go +++ b/pkg/parser/native/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExNative } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/oneinch/parser.go b/pkg/parser/oneinch/parser.go index 4c06aab..28166af 100644 --- a/pkg/parser/oneinch/parser.go +++ b/pkg/parser/oneinch/parser.go @@ -217,3 +217,7 @@ func (p *Parser) decodeOutput(output string) (string, string, string, error) { func (p *Parser) Exchange() string { return parser.Ex1Inch } + +func (p *Parser) UseTraceCall() bool { + return true +} diff --git a/pkg/parser/oneinchv6/parser.go b/pkg/parser/oneinchv6/parser.go index 05a7f40..ff8edbc 100644 --- a/pkg/parser/oneinchv6/parser.go +++ b/pkg/parser/oneinchv6/parser.go @@ -233,3 +233,7 @@ func (p *Parser) decodeOutput(output string) (string, string, string, error) { func (p *Parser) Exchange() string { return parser.Ex1InchV6 } + +func (p *Parser) UseTraceCall() bool { + return true +} diff --git a/pkg/parser/paraswap/parser.go b/pkg/parser/paraswap/parser.go index ffef791..bbc1d6b 100644 --- a/pkg/parser/paraswap/parser.go +++ b/pkg/parser/paraswap/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExParaswap } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index b345e28..86516ea 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -25,4 +25,5 @@ type Parser interface { Parse(log types.Log, blockTime uint64) (storage.TradeLog, error) Topics() []string Exchange() string + UseTraceCall() bool } diff --git a/pkg/parser/tokenlon/parser.go b/pkg/parser/tokenlon/parser.go index 187c1d9..dfbfa85 100644 --- a/pkg/parser/tokenlon/parser.go +++ b/pkg/parser/tokenlon/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExTokenlon } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/uniswapx/abi.json b/pkg/parser/uniswapx/abi.json new file mode 100644 index 0000000..c902f1f --- /dev/null +++ b/pkg/parser/uniswapx/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"contract IPermit2","name":"_permit2","type":"address"},{"internalType":"address","name":"_protocolFeeOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeadlineBeforeEndTime","type":"error"},{"inputs":[{"internalType":"address","name":"duplicateToken","type":"address"}],"name":"DuplicateFeeOutput","type":"error"},{"inputs":[],"name":"EndTimeBeforeStartTime","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"FeeTooLarge","type":"error"},{"inputs":[],"name":"IncorrectAmounts","type":"error"},{"inputs":[],"name":"InputAndOutputDecay","type":"error"},{"inputs":[],"name":"InsufficientEth","type":"error"},{"inputs":[],"name":"InvalidCosignature","type":"error"},{"inputs":[],"name":"InvalidCosignerInput","type":"error"},{"inputs":[],"name":"InvalidCosignerOutput","type":"error"},{"inputs":[{"internalType":"address","name":"feeToken","type":"address"}],"name":"InvalidFeeToken","type":"error"},{"inputs":[],"name":"InvalidReactor","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NoExclusiveOverride","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"filler","type":"address"},{"indexed":true,"internalType":"address","name":"swapper","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Fill","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFeeController","type":"address"},{"indexed":false,"internalType":"address","name":"newFeeController","type":"address"}],"name":"ProtocolFeeControllerSet","type":"event"},{"inputs":[{"components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct SignedOrder","name":"order","type":"tuple"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct SignedOrder[]","name":"orders","type":"tuple[]"}],"name":"executeBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct SignedOrder[]","name":"orders","type":"tuple[]"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"executeBatchWithCallback","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct SignedOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"executeWithCallback","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeController","outputs":[{"internalType":"contract IProtocolFeeController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newFeeController","type":"address"}],"name":"setProtocolFeeController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] diff --git a/pkg/parser/uniswapx/gen.sh b/pkg/parser/uniswapx/gen.sh new file mode 100755 index 0000000..ed0787f --- /dev/null +++ b/pkg/parser/uniswapx/gen.sh @@ -0,0 +1 @@ +abigen --abi=abi.json --pkg=uniswapx --out=uniswapx.go diff --git a/pkg/parser/uniswapx/parser.go b/pkg/parser/uniswapx/parser.go new file mode 100644 index 0000000..ac70143 --- /dev/null +++ b/pkg/parser/uniswapx/parser.go @@ -0,0 +1,308 @@ +package uniswapx + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + + "github.com/KyberNetwork/tradelogs/internal/types" + "github.com/KyberNetwork/tradelogs/pkg/decoder" + "github.com/KyberNetwork/tradelogs/pkg/parser" + "github.com/KyberNetwork/tradelogs/pkg/storage" + "github.com/KyberNetwork/tradelogs/pkg/tracecall" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethereumTypes "github.com/ethereum/go-ethereum/core/types" +) + +const ( + FilledEvent = "Fill" + TransferEvent = "Transfer" +) + +type ResolvedOrder struct { + Info struct { + Reactor common.Address "json:\"reactor\"" + Swapper common.Address "json:\"swapper\"" + Nonce *big.Int "json:\"nonce\"" + Deadline *big.Int "json:\"deadline\"" + AdditionalValidationContract common.Address "json:\"additionalValidationContract\"" + AdditionalValidationData []uint8 "json:\"additionalValidationData\"" + } "json:\"info\"" + Cosigner common.Address "json:\"cosigner\"" + InputToken struct { + InputToken common.Address "json:\"inputToken\"" + InputStartAmount *big.Int "json:\"inputStartAmount\"" + InputEndAmount *big.Int "json:\"inputEndAmount\"" + } "json:\"inputToken\"" + Outputs []struct { + Token common.Address "json:\"token\"" + StartAmount *big.Int "json:\"startAmount\"" + EndAmount *big.Int "json:\"endAmount\"" + Recipient common.Address "json:\"recipient\"" + } "json:\"outputs\"" + CosignerData struct { + DecayStartTime *big.Int "json:\"decayStartTime\"" + DecayEndTime *big.Int "json:\"decayEndTime\"" + ExclusiveFiller common.Address "json:\"exclusiveFiller\"" + ExclusivityOverrideBps *big.Int "json:\"exclusivityOverrideBps\"" + InputOverride *big.Int "json:\"inputOverride\"" + OutputOverrides []struct { + Override *big.Int "json:\"override\"" + } "json:\"outputOverrides\"" + } + Cosignature []uint8 "json:\"cosignature\"" +} + +var ( + ErrInvalidOneInchFilledTopic = errors.New("invalid uniswapx order filled topic") + ErrUpdateOrder = errors.New("can't update order") +) + +type Parser struct { + abi *abi.ABI + ps *UniswapxFilterer + eventHash string + traceCalls *tracecall.Cache + orderArguments abi.Arguments +} + +func MustNewParser(cache *tracecall.Cache) *Parser { + ps, err := NewUniswapxFilterer(common.Address{}, nil) + if err != nil { + panic(err) + } + ab, err := UniswapxMetaData.GetAbi() + if err != nil { + panic(err) + } + event, ok := ab.Events[FilledEvent] + if !ok { + panic(fmt.Sprintf("no such event: %s", FilledEvent)) + } + + orderTuple, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "info", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "reactor", Type: "address"}, + {Name: "swapper", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + {Name: "deadline", Type: "uint256"}, + {Name: "additionalValidationContract", Type: "address"}, + {Name: "additionalValidationData", Type: "bytes"}}, + }, + {Name: "cosigner", Type: "address"}, + {Name: "inputToken", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "inputToken", Type: "address"}, + {Name: "inputStartAmount", Type: "uint256"}, + {Name: "inputEndAmount", Type: "uint256"}}, + }, + {Name: "outputs", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ + {Name: "token", Type: "address"}, + {Name: "startAmount", Type: "uint256"}, + {Name: "endAmount", Type: "uint256"}, + {Name: "recipient", Type: "address"}, + }}, + {Name: "cosignerData", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "decayStartTime", Type: "uint256"}, + {Name: "decayEndTime", Type: "uint256"}, + {Name: "exclusiveFiller", Type: "address"}, + {Name: "exclusivityOverrideBps", Type: "uint256"}, + {Name: "inputOverride", Type: "uint256"}, + {Name: "outputOverrides", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ + {Name: "override", Type: "uint256"}}}}, + }, + {Name: "cosignature", Type: "bytes"}, + }) + if err != nil { + panic("cant create order abi type") + } + + return &Parser{ + ps: ps, + abi: ab, + eventHash: event.ID.String(), + traceCalls: cache, + orderArguments: abi.Arguments{{Type: orderTuple}}, + } +} + +func (p *Parser) Topics() []string { + return []string{ + p.eventHash, + } +} + +func (p *Parser) Parse(log ethereumTypes.Log, blockTime uint64) (storage.TradeLog, error) { + if len(log.Topics) > 0 && log.Topics[0].Hex() != p.eventHash { + return storage.TradeLog{}, ErrInvalidOneInchFilledTopic + } + e, err := p.ps.ParseFill(log) + if err != nil { + return storage.TradeLog{}, err + } + order := storage.TradeLog{ + OrderHash: common.Hash(e.OrderHash).String(), + ContractAddress: e.Raw.Address.String(), + BlockNumber: e.Raw.BlockNumber, + TxHash: e.Raw.TxHash.String(), + LogIndex: uint64(e.Raw.Index), + Timestamp: blockTime * 1000, + EventHash: p.eventHash, + Maker: e.Filler.String(), + Taker: e.Swapper.String(), + } + + order, err = p.detectRfqTrade(order) + if err != nil { + return order, err + } + return order, nil +} + +func (p *Parser) detectRfqTrade(order storage.TradeLog) (storage.TradeLog, error) { + traceCall, err := p.traceCalls.GetTraceCall(order.TxHash) + if err != nil { + return order, err + } + + order, err = p.recursiveDetectRFQTrades(order, traceCall) + if err != nil { + return order, err + } + return order, nil +} + +func (p *Parser) recursiveDetectRFQTrades(order storage.TradeLog, call types.CallFrame) (storage.TradeLog, error) { + for _, l := range call.Logs { + if len(l.Topics) < 2 { + continue + } + if l.Topics[0].String() != p.eventHash || l.Topics[1].String() != order.OrderHash { + continue + } + input, err := decoder.Decode(p.abi, call.Input) + if err != nil { + continue + } + if len(input.Params) == 0 { + continue + } + inputOrder, ok := input.Params[0].Value.(struct { + Order []uint8 `json:"order"` + Sig []uint8 `json:"sig"` + }) + if !ok { + inputOrders, ok := input.Params[0].Value.([]struct { + Order []uint8 `json:"order"` + Sig []uint8 `json:"sig"` + }) + if !ok || len(inputOrders) == 0 { + continue + } + inputOrder = inputOrders[0] + } + + parsedOrder, err := p.orderArguments.Unpack(inputOrder.Order) + if err != nil { + continue + } + finalOrder, err := p.updateOrder(call.From, order, parsedOrder) + if err != nil { + continue + } + return finalOrder, nil + } + + for i := range call.Calls { + order, err := p.recursiveDetectRFQTrades(order, call.Calls[i]) + if err == nil { + return order, nil + } + } + return order, ErrUpdateOrder +} + +func (p *Parser) updateOrder(from string, internal storage.TradeLog, parsed []interface{}) (storage.TradeLog, error) { + data, err := json.Marshal(parsed) + if err != nil { + return storage.TradeLog{}, err + } + var resolvedOrder []ResolvedOrder + if err = json.Unmarshal(data, &resolvedOrder); err != nil { + return storage.TradeLog{}, err + } + if len(resolvedOrder) == 0 || len(resolvedOrder[0].Outputs) == 0 { + return storage.TradeLog{}, err + } + + order := resolvedOrder[0] + if order.CosignerData.InputOverride.Cmp(big.NewInt(0)) != 0 { + order.InputToken.InputStartAmount = order.CosignerData.InputOverride + } + for i := range order.Outputs { + if order.CosignerData.OutputOverrides[i].Override.Cmp(big.NewInt(0)) != 0 { + order.Outputs[i].StartAmount = order.CosignerData.OutputOverrides[i].Override + } + } + + internal.TakerToken = order.InputToken.InputToken.String() + internal.MakerToken = order.Outputs[0].Token.String() + + internal.TakerTokenAmount = decay(order.InputToken.InputStartAmount, + order.InputToken.InputEndAmount, + order.CosignerData.DecayStartTime, + order.CosignerData.DecayEndTime, + big.NewInt(int64(internal.Timestamp/1000))).String() + + makerAmount := big.NewInt(0) + for _, o := range order.Outputs { + makerAmount = makerAmount.Add(makerAmount, decay(o.StartAmount, o.EndAmount, + order.CosignerData.DecayStartTime, order.CosignerData.DecayEndTime, + big.NewInt(int64(internal.Timestamp/1000)))) + } + internal.MakerTokenAmount = makerAmount.String() + return internal, nil +} + +func decay(startAmount, endAmount, decayStartTime, decayEndTime, blockTime *big.Int) (decayedAmount *big.Int) { + decayedAmount = new(big.Int) + + if decayEndTime.Cmp(blockTime) <= 0 { + decayedAmount.Set(endAmount) + } else if decayStartTime.Cmp(blockTime) >= 0 { + decayedAmount.Set(startAmount) + } else { + elapsed := new(big.Int).Sub(blockTime, decayStartTime) + duration := new(big.Int).Sub(decayEndTime, decayStartTime) + + if endAmount.Cmp(startAmount) < 0 { + diff := new(big.Int).Sub(startAmount, endAmount) + decayedAmount = new(big.Int).Sub(startAmount, mulDiv(diff, elapsed, duration)) + } else { + diff := new(big.Int).Sub(endAmount, startAmount) + decayedAmount = new(big.Int).Add(startAmount, mulDiv(diff, elapsed, duration)) + } + } + return +} + +// func handleOverride(amount, exclusivityOverrideBps, BPS *big.Int) *big.Int { +// return mulDiv(amount, new(big.Int).Add(exclusivityOverrideBps, BPS), BPS) +// } + +func mulDiv(a, b, c *big.Int) *big.Int { + return new(big.Int).Div(new(big.Int).Mul(a, b), c) +} + +// func checkExclusivity(exclusive, sender common.Address, exclusivityEndTime, ts uint64) bool { +// return exclusive == common.Address{} || ts > exclusivityEndTime || exclusive == sender +// } + +func (p *Parser) Exchange() string { + return parser.ExUniswapX +} + +func (p *Parser) UseTraceCall() bool { + return true +} diff --git a/pkg/parser/uniswapx/uniswap_test.go b/pkg/parser/uniswapx/uniswap_test.go new file mode 100644 index 0000000..aefa74d --- /dev/null +++ b/pkg/parser/uniswapx/uniswap_test.go @@ -0,0 +1,71 @@ +package uniswapx // nolint: testpackage + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "net/http" + "testing" + + "github.com/KyberNetwork/tradelogs/pkg/rpcnode" + "github.com/KyberNetwork/tradelogs/pkg/tracecall" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" +) + +const rpcURL = "" + +func TestFetchEvent(t *testing.T) { + t.Skip("Need to add the rpc url that enables the trace call JSON-RPC") + rpcClient, err := rpcnode.NewClient(http.DefaultClient, rpcURL) + if err != nil { + panic(err) + } + traceCalls := tracecall.NewCache(rpcClient) + p := MustNewParser(traceCalls) + require.Equal(t, p.abi.Events[FilledEvent].ID, common.HexToHash("0x78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66")) + client, err := ethclient.Dial("https://ethereum.kyberengineering.io") + require.NoError(t, err) + logs, err := client.FilterLogs(context.Background(), ethereum.FilterQuery{ + BlockHash: nil, + FromBlock: big.NewInt(19719300), + ToBlock: big.NewInt(19719300), + Addresses: nil, + Topics: [][]common.Hash{ + { + p.abi.Events[FilledEvent].ID, + }, + }, + }) + require.NoError(t, err) + d, err := json.Marshal(logs) + require.NoError(t, err) + t.Log(string(d)) +} + +func TestParseEvent(t *testing.T) { + t.Skip("Need to add the rpc url that enables the trace call JSON-RPC") + eventRaw := `{"address":"0x3867393cc6ea7b0414c2c3e1d9fe7cea987fd066","topics":["0x78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66","0x510fd6dd82e657a1bc4e007ee563925923c5896fecc6996e491adcaff6c8a528","0x000000000000000000000000ff8ba4d1fc3762f6154cc942ccf30049a2a0cec6","0x000000000000000000000000250a94c03b9b57c93cc5549760d59d6eacfb136d"],"data":"0x04683239f5ccb91d719180e8d856523bf095571534b3cd850e678dd61919c153","blockNumber":"0x12ce484","transactionHash":"0xcbd70c12e81d3521ca0e96dc887ae6653063f75dbdcd943a5ee406fa30446619","transactionIndex":"0x81","blockHash":"0x32fc731de2f9509f6c829995e31b843c28594b866b39f9009cac65dbb8bee173","logIndex":"0x10c","removed":false}` + event := types.Log{} + err := json.Unmarshal([]byte(eventRaw), &event) + require.NoError(t, err) + rpcClient, err := rpcnode.NewClient(http.DefaultClient, rpcURL) + if err != nil { + panic(err) + } + traceCalls := tracecall.NewCache(rpcClient) + p := MustNewParser(traceCalls) + log, err := p.Parse(event, 1713889895) + require.NoError(t, err) + fmt.Printf("%+v\n", log) + require.Equal(t, log.EventHash, p.eventHash) + require.Equal(t, log.Maker, "0xff8Ba4D1fC3762f6154cc942CCF30049A2A0cEC6") + require.Equal(t, log.Taker, "0x250A94C03b9b57C93CC5549760D59d6eAcfB136d") + require.Equal(t, log.MakerTokenAmount, "42282994361466557") + require.Equal(t, log.TakerTokenAmount, "146889265") + t.Log(log) +} diff --git a/pkg/parser/uniswapx/uniswapx.go b/pkg/parser/uniswapx/uniswapx.go new file mode 100644 index 0000000..8c54b79 --- /dev/null +++ b/pkg/parser/uniswapx/uniswapx.go @@ -0,0 +1,878 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package uniswapx + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// SignedOrder is an auto generated low-level Go binding around an user-defined struct. +type SignedOrder struct { + Order []byte + Sig []byte +} + +// UniswapxMetaData contains all meta data concerning the Uniswapx contract. +var UniswapxMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractIPermit2\",\"name\":\"_permit2\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_protocolFeeOwner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"DeadlineBeforeEndTime\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"duplicateToken\",\"type\":\"address\"}],\"name\":\"DuplicateFeeOutput\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EndTimeBeforeStartTime\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"FeeTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InputAndOutputDecay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientEth\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCosignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCosignerInput\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCosignerOutput\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"InvalidFeeToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReactor\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoExclusiveOverride\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"orderHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"filler\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"swapper\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"Fill\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeController\",\"type\":\"address\"}],\"name\":\"ProtocolFeeControllerSet\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"structSignedOrder\",\"name\":\"order\",\"type\":\"tuple\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"structSignedOrder[]\",\"name\":\"orders\",\"type\":\"tuple[]\"}],\"name\":\"executeBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"structSignedOrder[]\",\"name\":\"orders\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"callbackData\",\"type\":\"bytes\"}],\"name\":\"executeBatchWithCallback\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"order\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"structSignedOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"callbackData\",\"type\":\"bytes\"}],\"name\":\"executeWithCallback\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeController\",\"outputs\":[{\"internalType\":\"contractIProtocolFeeController\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contractIPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newFeeController\",\"type\":\"address\"}],\"name\":\"setProtocolFeeController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", +} + +// UniswapxABI is the input ABI used to generate the binding from. +// Deprecated: Use UniswapxMetaData.ABI instead. +var UniswapxABI = UniswapxMetaData.ABI + +// Uniswapx is an auto generated Go binding around an Ethereum contract. +type Uniswapx struct { + UniswapxCaller // Read-only binding to the contract + UniswapxTransactor // Write-only binding to the contract + UniswapxFilterer // Log filterer for contract events +} + +// UniswapxCaller is an auto generated read-only Go binding around an Ethereum contract. +type UniswapxCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniswapxTransactor is an auto generated write-only Go binding around an Ethereum contract. +type UniswapxTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniswapxFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type UniswapxFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniswapxSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type UniswapxSession struct { + Contract *Uniswapx // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UniswapxCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type UniswapxCallerSession struct { + Contract *UniswapxCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// UniswapxTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type UniswapxTransactorSession struct { + Contract *UniswapxTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UniswapxRaw is an auto generated low-level Go binding around an Ethereum contract. +type UniswapxRaw struct { + Contract *Uniswapx // Generic contract binding to access the raw methods on +} + +// UniswapxCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type UniswapxCallerRaw struct { + Contract *UniswapxCaller // Generic read-only contract binding to access the raw methods on +} + +// UniswapxTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type UniswapxTransactorRaw struct { + Contract *UniswapxTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewUniswapx creates a new instance of Uniswapx, bound to a specific deployed contract. +func NewUniswapx(address common.Address, backend bind.ContractBackend) (*Uniswapx, error) { + contract, err := bindUniswapx(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Uniswapx{UniswapxCaller: UniswapxCaller{contract: contract}, UniswapxTransactor: UniswapxTransactor{contract: contract}, UniswapxFilterer: UniswapxFilterer{contract: contract}}, nil +} + +// NewUniswapxCaller creates a new read-only instance of Uniswapx, bound to a specific deployed contract. +func NewUniswapxCaller(address common.Address, caller bind.ContractCaller) (*UniswapxCaller, error) { + contract, err := bindUniswapx(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &UniswapxCaller{contract: contract}, nil +} + +// NewUniswapxTransactor creates a new write-only instance of Uniswapx, bound to a specific deployed contract. +func NewUniswapxTransactor(address common.Address, transactor bind.ContractTransactor) (*UniswapxTransactor, error) { + contract, err := bindUniswapx(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &UniswapxTransactor{contract: contract}, nil +} + +// NewUniswapxFilterer creates a new log filterer instance of Uniswapx, bound to a specific deployed contract. +func NewUniswapxFilterer(address common.Address, filterer bind.ContractFilterer) (*UniswapxFilterer, error) { + contract, err := bindUniswapx(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &UniswapxFilterer{contract: contract}, nil +} + +// bindUniswapx binds a generic wrapper to an already deployed contract. +func bindUniswapx(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := UniswapxMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Uniswapx *UniswapxRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Uniswapx.Contract.UniswapxCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Uniswapx *UniswapxRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Uniswapx.Contract.UniswapxTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Uniswapx *UniswapxRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Uniswapx.Contract.UniswapxTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Uniswapx *UniswapxCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Uniswapx.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Uniswapx *UniswapxTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Uniswapx.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Uniswapx *UniswapxTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Uniswapx.Contract.contract.Transact(opts, method, params...) +} + +// FeeController is a free data retrieval call binding the contract method 0x6999b377. +// +// Solidity: function feeController() view returns(address) +func (_Uniswapx *UniswapxCaller) FeeController(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Uniswapx.contract.Call(opts, &out, "feeController") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// FeeController is a free data retrieval call binding the contract method 0x6999b377. +// +// Solidity: function feeController() view returns(address) +func (_Uniswapx *UniswapxSession) FeeController() (common.Address, error) { + return _Uniswapx.Contract.FeeController(&_Uniswapx.CallOpts) +} + +// FeeController is a free data retrieval call binding the contract method 0x6999b377. +// +// Solidity: function feeController() view returns(address) +func (_Uniswapx *UniswapxCallerSession) FeeController() (common.Address, error) { + return _Uniswapx.Contract.FeeController(&_Uniswapx.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Uniswapx *UniswapxCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Uniswapx.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Uniswapx *UniswapxSession) Owner() (common.Address, error) { + return _Uniswapx.Contract.Owner(&_Uniswapx.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Uniswapx *UniswapxCallerSession) Owner() (common.Address, error) { + return _Uniswapx.Contract.Owner(&_Uniswapx.CallOpts) +} + +// Permit2 is a free data retrieval call binding the contract method 0x12261ee7. +// +// Solidity: function permit2() view returns(address) +func (_Uniswapx *UniswapxCaller) Permit2(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Uniswapx.contract.Call(opts, &out, "permit2") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Permit2 is a free data retrieval call binding the contract method 0x12261ee7. +// +// Solidity: function permit2() view returns(address) +func (_Uniswapx *UniswapxSession) Permit2() (common.Address, error) { + return _Uniswapx.Contract.Permit2(&_Uniswapx.CallOpts) +} + +// Permit2 is a free data retrieval call binding the contract method 0x12261ee7. +// +// Solidity: function permit2() view returns(address) +func (_Uniswapx *UniswapxCallerSession) Permit2() (common.Address, error) { + return _Uniswapx.Contract.Permit2(&_Uniswapx.CallOpts) +} + +// Execute is a paid mutator transaction binding the contract method 0x3f62192e. +// +// Solidity: function execute((bytes,bytes) order) payable returns() +func (_Uniswapx *UniswapxTransactor) Execute(opts *bind.TransactOpts, order SignedOrder) (*types.Transaction, error) { + return _Uniswapx.contract.Transact(opts, "execute", order) +} + +// Execute is a paid mutator transaction binding the contract method 0x3f62192e. +// +// Solidity: function execute((bytes,bytes) order) payable returns() +func (_Uniswapx *UniswapxSession) Execute(order SignedOrder) (*types.Transaction, error) { + return _Uniswapx.Contract.Execute(&_Uniswapx.TransactOpts, order) +} + +// Execute is a paid mutator transaction binding the contract method 0x3f62192e. +// +// Solidity: function execute((bytes,bytes) order) payable returns() +func (_Uniswapx *UniswapxTransactorSession) Execute(order SignedOrder) (*types.Transaction, error) { + return _Uniswapx.Contract.Execute(&_Uniswapx.TransactOpts, order) +} + +// ExecuteBatch is a paid mutator transaction binding the contract method 0x0d7a16c3. +// +// Solidity: function executeBatch((bytes,bytes)[] orders) payable returns() +func (_Uniswapx *UniswapxTransactor) ExecuteBatch(opts *bind.TransactOpts, orders []SignedOrder) (*types.Transaction, error) { + return _Uniswapx.contract.Transact(opts, "executeBatch", orders) +} + +// ExecuteBatch is a paid mutator transaction binding the contract method 0x0d7a16c3. +// +// Solidity: function executeBatch((bytes,bytes)[] orders) payable returns() +func (_Uniswapx *UniswapxSession) ExecuteBatch(orders []SignedOrder) (*types.Transaction, error) { + return _Uniswapx.Contract.ExecuteBatch(&_Uniswapx.TransactOpts, orders) +} + +// ExecuteBatch is a paid mutator transaction binding the contract method 0x0d7a16c3. +// +// Solidity: function executeBatch((bytes,bytes)[] orders) payable returns() +func (_Uniswapx *UniswapxTransactorSession) ExecuteBatch(orders []SignedOrder) (*types.Transaction, error) { + return _Uniswapx.Contract.ExecuteBatch(&_Uniswapx.TransactOpts, orders) +} + +// ExecuteBatchWithCallback is a paid mutator transaction binding the contract method 0x13fb72c7. +// +// Solidity: function executeBatchWithCallback((bytes,bytes)[] orders, bytes callbackData) payable returns() +func (_Uniswapx *UniswapxTransactor) ExecuteBatchWithCallback(opts *bind.TransactOpts, orders []SignedOrder, callbackData []byte) (*types.Transaction, error) { + return _Uniswapx.contract.Transact(opts, "executeBatchWithCallback", orders, callbackData) +} + +// ExecuteBatchWithCallback is a paid mutator transaction binding the contract method 0x13fb72c7. +// +// Solidity: function executeBatchWithCallback((bytes,bytes)[] orders, bytes callbackData) payable returns() +func (_Uniswapx *UniswapxSession) ExecuteBatchWithCallback(orders []SignedOrder, callbackData []byte) (*types.Transaction, error) { + return _Uniswapx.Contract.ExecuteBatchWithCallback(&_Uniswapx.TransactOpts, orders, callbackData) +} + +// ExecuteBatchWithCallback is a paid mutator transaction binding the contract method 0x13fb72c7. +// +// Solidity: function executeBatchWithCallback((bytes,bytes)[] orders, bytes callbackData) payable returns() +func (_Uniswapx *UniswapxTransactorSession) ExecuteBatchWithCallback(orders []SignedOrder, callbackData []byte) (*types.Transaction, error) { + return _Uniswapx.Contract.ExecuteBatchWithCallback(&_Uniswapx.TransactOpts, orders, callbackData) +} + +// ExecuteWithCallback is a paid mutator transaction binding the contract method 0x0d335884. +// +// Solidity: function executeWithCallback((bytes,bytes) order, bytes callbackData) payable returns() +func (_Uniswapx *UniswapxTransactor) ExecuteWithCallback(opts *bind.TransactOpts, order SignedOrder, callbackData []byte) (*types.Transaction, error) { + return _Uniswapx.contract.Transact(opts, "executeWithCallback", order, callbackData) +} + +// ExecuteWithCallback is a paid mutator transaction binding the contract method 0x0d335884. +// +// Solidity: function executeWithCallback((bytes,bytes) order, bytes callbackData) payable returns() +func (_Uniswapx *UniswapxSession) ExecuteWithCallback(order SignedOrder, callbackData []byte) (*types.Transaction, error) { + return _Uniswapx.Contract.ExecuteWithCallback(&_Uniswapx.TransactOpts, order, callbackData) +} + +// ExecuteWithCallback is a paid mutator transaction binding the contract method 0x0d335884. +// +// Solidity: function executeWithCallback((bytes,bytes) order, bytes callbackData) payable returns() +func (_Uniswapx *UniswapxTransactorSession) ExecuteWithCallback(order SignedOrder, callbackData []byte) (*types.Transaction, error) { + return _Uniswapx.Contract.ExecuteWithCallback(&_Uniswapx.TransactOpts, order, callbackData) +} + +// SetProtocolFeeController is a paid mutator transaction binding the contract method 0x2d771389. +// +// Solidity: function setProtocolFeeController(address _newFeeController) returns() +func (_Uniswapx *UniswapxTransactor) SetProtocolFeeController(opts *bind.TransactOpts, _newFeeController common.Address) (*types.Transaction, error) { + return _Uniswapx.contract.Transact(opts, "setProtocolFeeController", _newFeeController) +} + +// SetProtocolFeeController is a paid mutator transaction binding the contract method 0x2d771389. +// +// Solidity: function setProtocolFeeController(address _newFeeController) returns() +func (_Uniswapx *UniswapxSession) SetProtocolFeeController(_newFeeController common.Address) (*types.Transaction, error) { + return _Uniswapx.Contract.SetProtocolFeeController(&_Uniswapx.TransactOpts, _newFeeController) +} + +// SetProtocolFeeController is a paid mutator transaction binding the contract method 0x2d771389. +// +// Solidity: function setProtocolFeeController(address _newFeeController) returns() +func (_Uniswapx *UniswapxTransactorSession) SetProtocolFeeController(_newFeeController common.Address) (*types.Transaction, error) { + return _Uniswapx.Contract.SetProtocolFeeController(&_Uniswapx.TransactOpts, _newFeeController) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Uniswapx *UniswapxTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _Uniswapx.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Uniswapx *UniswapxSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Uniswapx.Contract.TransferOwnership(&_Uniswapx.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Uniswapx *UniswapxTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Uniswapx.Contract.TransferOwnership(&_Uniswapx.TransactOpts, newOwner) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_Uniswapx *UniswapxTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Uniswapx.contract.RawTransact(opts, nil) // calldata is disallowed for receive function +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_Uniswapx *UniswapxSession) Receive() (*types.Transaction, error) { + return _Uniswapx.Contract.Receive(&_Uniswapx.TransactOpts) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_Uniswapx *UniswapxTransactorSession) Receive() (*types.Transaction, error) { + return _Uniswapx.Contract.Receive(&_Uniswapx.TransactOpts) +} + +// UniswapxFillIterator is returned from FilterFill and is used to iterate over the raw logs and unpacked data for Fill events raised by the Uniswapx contract. +type UniswapxFillIterator struct { + Event *UniswapxFill // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *UniswapxFillIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(UniswapxFill) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(UniswapxFill) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *UniswapxFillIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *UniswapxFillIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// UniswapxFill represents a Fill event raised by the Uniswapx contract. +type UniswapxFill struct { + OrderHash [32]byte + Filler common.Address + Swapper common.Address + Nonce *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFill is a free log retrieval operation binding the contract event 0x78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66. +// +// Solidity: event Fill(bytes32 indexed orderHash, address indexed filler, address indexed swapper, uint256 nonce) +func (_Uniswapx *UniswapxFilterer) FilterFill(opts *bind.FilterOpts, orderHash [][32]byte, filler []common.Address, swapper []common.Address) (*UniswapxFillIterator, error) { + + var orderHashRule []interface{} + for _, orderHashItem := range orderHash { + orderHashRule = append(orderHashRule, orderHashItem) + } + var fillerRule []interface{} + for _, fillerItem := range filler { + fillerRule = append(fillerRule, fillerItem) + } + var swapperRule []interface{} + for _, swapperItem := range swapper { + swapperRule = append(swapperRule, swapperItem) + } + + logs, sub, err := _Uniswapx.contract.FilterLogs(opts, "Fill", orderHashRule, fillerRule, swapperRule) + if err != nil { + return nil, err + } + return &UniswapxFillIterator{contract: _Uniswapx.contract, event: "Fill", logs: logs, sub: sub}, nil +} + +// WatchFill is a free log subscription operation binding the contract event 0x78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66. +// +// Solidity: event Fill(bytes32 indexed orderHash, address indexed filler, address indexed swapper, uint256 nonce) +func (_Uniswapx *UniswapxFilterer) WatchFill(opts *bind.WatchOpts, sink chan<- *UniswapxFill, orderHash [][32]byte, filler []common.Address, swapper []common.Address) (event.Subscription, error) { + + var orderHashRule []interface{} + for _, orderHashItem := range orderHash { + orderHashRule = append(orderHashRule, orderHashItem) + } + var fillerRule []interface{} + for _, fillerItem := range filler { + fillerRule = append(fillerRule, fillerItem) + } + var swapperRule []interface{} + for _, swapperItem := range swapper { + swapperRule = append(swapperRule, swapperItem) + } + + logs, sub, err := _Uniswapx.contract.WatchLogs(opts, "Fill", orderHashRule, fillerRule, swapperRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(UniswapxFill) + if err := _Uniswapx.contract.UnpackLog(event, "Fill", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFill is a log parse operation binding the contract event 0x78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66. +// +// Solidity: event Fill(bytes32 indexed orderHash, address indexed filler, address indexed swapper, uint256 nonce) +func (_Uniswapx *UniswapxFilterer) ParseFill(log types.Log) (*UniswapxFill, error) { + event := new(UniswapxFill) + if err := _Uniswapx.contract.UnpackLog(event, "Fill", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// UniswapxOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Uniswapx contract. +type UniswapxOwnershipTransferredIterator struct { + Event *UniswapxOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *UniswapxOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(UniswapxOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(UniswapxOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *UniswapxOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *UniswapxOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// UniswapxOwnershipTransferred represents a OwnershipTransferred event raised by the Uniswapx contract. +type UniswapxOwnershipTransferred struct { + User common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed user, address indexed newOwner) +func (_Uniswapx *UniswapxFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, user []common.Address, newOwner []common.Address) (*UniswapxOwnershipTransferredIterator, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Uniswapx.contract.FilterLogs(opts, "OwnershipTransferred", userRule, newOwnerRule) + if err != nil { + return nil, err + } + return &UniswapxOwnershipTransferredIterator{contract: _Uniswapx.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed user, address indexed newOwner) +func (_Uniswapx *UniswapxFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *UniswapxOwnershipTransferred, user []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Uniswapx.contract.WatchLogs(opts, "OwnershipTransferred", userRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(UniswapxOwnershipTransferred) + if err := _Uniswapx.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed user, address indexed newOwner) +func (_Uniswapx *UniswapxFilterer) ParseOwnershipTransferred(log types.Log) (*UniswapxOwnershipTransferred, error) { + event := new(UniswapxOwnershipTransferred) + if err := _Uniswapx.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// UniswapxProtocolFeeControllerSetIterator is returned from FilterProtocolFeeControllerSet and is used to iterate over the raw logs and unpacked data for ProtocolFeeControllerSet events raised by the Uniswapx contract. +type UniswapxProtocolFeeControllerSetIterator struct { + Event *UniswapxProtocolFeeControllerSet // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *UniswapxProtocolFeeControllerSetIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(UniswapxProtocolFeeControllerSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(UniswapxProtocolFeeControllerSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *UniswapxProtocolFeeControllerSetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *UniswapxProtocolFeeControllerSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// UniswapxProtocolFeeControllerSet represents a ProtocolFeeControllerSet event raised by the Uniswapx contract. +type UniswapxProtocolFeeControllerSet struct { + OldFeeController common.Address + NewFeeController common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterProtocolFeeControllerSet is a free log retrieval operation binding the contract event 0xb904ae9529e373e48bc82df4326cceaf1b4c472babf37f5b7dec46fecc6b53e0. +// +// Solidity: event ProtocolFeeControllerSet(address oldFeeController, address newFeeController) +func (_Uniswapx *UniswapxFilterer) FilterProtocolFeeControllerSet(opts *bind.FilterOpts) (*UniswapxProtocolFeeControllerSetIterator, error) { + + logs, sub, err := _Uniswapx.contract.FilterLogs(opts, "ProtocolFeeControllerSet") + if err != nil { + return nil, err + } + return &UniswapxProtocolFeeControllerSetIterator{contract: _Uniswapx.contract, event: "ProtocolFeeControllerSet", logs: logs, sub: sub}, nil +} + +// WatchProtocolFeeControllerSet is a free log subscription operation binding the contract event 0xb904ae9529e373e48bc82df4326cceaf1b4c472babf37f5b7dec46fecc6b53e0. +// +// Solidity: event ProtocolFeeControllerSet(address oldFeeController, address newFeeController) +func (_Uniswapx *UniswapxFilterer) WatchProtocolFeeControllerSet(opts *bind.WatchOpts, sink chan<- *UniswapxProtocolFeeControllerSet) (event.Subscription, error) { + + logs, sub, err := _Uniswapx.contract.WatchLogs(opts, "ProtocolFeeControllerSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(UniswapxProtocolFeeControllerSet) + if err := _Uniswapx.contract.UnpackLog(event, "ProtocolFeeControllerSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseProtocolFeeControllerSet is a log parse operation binding the contract event 0xb904ae9529e373e48bc82df4326cceaf1b4c472babf37f5b7dec46fecc6b53e0. +// +// Solidity: event ProtocolFeeControllerSet(address oldFeeController, address newFeeController) +func (_Uniswapx *UniswapxFilterer) ParseProtocolFeeControllerSet(log types.Log) (*UniswapxProtocolFeeControllerSet, error) { + event := new(UniswapxProtocolFeeControllerSet) + if err := _Uniswapx.contract.UnpackLog(event, "ProtocolFeeControllerSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/pkg/parser/zxotc/parser.go b/pkg/parser/zxotc/parser.go index 08695de..42c5e04 100644 --- a/pkg/parser/zxotc/parser.go +++ b/pkg/parser/zxotc/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExZeroX } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/parser/zxrfq/parser.go b/pkg/parser/zxrfq/parser.go index 48a8601..641c2ef 100644 --- a/pkg/parser/zxrfq/parser.go +++ b/pkg/parser/zxrfq/parser.go @@ -77,3 +77,7 @@ func (p *Parser) Parse(log types.Log, blockTime uint64) (storage.TradeLog, error func (p *Parser) Exchange() string { return parser.ExZeroXRFQ } + +func (p *Parser) UseTraceCall() bool { + return false +} diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 9e5d39d..a71b45f 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -222,3 +222,21 @@ func (s *Storage) DeleteErrorLogsWithLogIndex(block uint64, logIndex uint) error } return nil } + +func (s *Storage) GetErrorLogsSince(t int64) ([]EVMLog, error) { + q, p, err := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar). + Select("*"). + From(errorLogsTable). + Where(squirrel.GtOrEq{"time": t}). + ToSql() + + if err != nil { + return nil, err + } + + var result []EVMLog + if err := s.db.Select(&result, q, p...); err != nil { + return nil, err + } + return result, nil +}