diff --git a/.gitignore b/.gitignore index 14e6cf8..89e19c2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ __pycache__ .env *.pyc docker-cfg/ca-certificates.crt +.idea* +privkey* +sample.csv diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/zeroEx/fillOrder.go b/zeroEx/fillOrder.go new file mode 100644 index 0000000..9b51959 --- /dev/null +++ b/zeroEx/fillOrder.go @@ -0,0 +1,128 @@ +package zeroEx + +import ( + "context" + "encoding/hex" + "flag" + "log" + "math/big" + "os" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/google/subcommands" + "github.com/notegio/massive/utils" + orCommon "github.com/notegio/openrelay/common" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/notegio/openrelay/exchangecontract" +) + +type fillOrder struct { + inputFileName string + outputFileName string + inputFile *os.File + outputFile *os.File +} + +func (p *fillOrder) FileNames() (string, string) { + return p.inputFileName, p.outputFileName +} + +func (p *fillOrder) SetIOFiles(inputFile, outputFile *os.File) { + p.inputFile, p.outputFile = inputFile, outputFile +} + +func (*fillOrder) Name() string { return "fill" } +func (*fillOrder) Synopsis() string { + return "Fills the given order" +} +func (*fillOrder) Usage() string { + return `msv 0x fill [--input FILE] [--output FILE] ETHEREUM_RPC_URL KEY_FILE AMOUNT_TO_FILL:` +} + +func (p *fillOrder) SetFlags(f *flag.FlagSet) { + f.StringVar(&p.inputFileName, "input", "", "Input file [stdin]") + f.StringVar(&p.outputFileName, "output", "", "Output file [stdout]") +} + +func (p *fillOrder) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { + if f.NArg() != 3 { + os.Stderr.WriteString(p.Usage()) + return subcommands.ExitUsageError + } + utils.SetIO(p) + conn, err := ethclient.Dial(f.Arg(0)) + if err != nil { + log.Printf("Error establishing Ethereum connection: %v", err.Error()) + return subcommands.ExitFailure + } + privKey, err := crypto.LoadECDSA(f.Arg(1)) + if err != nil { + log.Printf("Error loading key: %v", err.Error()) + return subcommands.ExitFailure + } + takerValue, ok := new(big.Int).SetString(f.Arg(2), 10) + if !ok { + log.Printf("Error processing argument: %v\n", f.Arg(2)) + return subcommands.ExitFailure + } + + for order := range orderScanner(p.inputFile) { + + exchange, err := exchangecontract.NewExchange(orCommon.ToGethAddress(order.ExchangeAddress), conn) + if err != nil { + log.Printf("Error intializing exchange contract '%v': '%v'", hex.EncodeToString(order.ExchangeAddress[:]), err.Error()) + return subcommands.ExitFailure + } + takerAddress := crypto.PubkeyToAddress(privKey.PublicKey) + + // Set the taker address + transactOpt := bind.NewKeyedTransactor(privKey) + transactOpt.From = takerAddress + + // Set the order Addresses + orderAddresses := [5]common.Address{ + orCommon.ToGethAddress(order.Maker), + orCommon.ToGethAddress(order.Taker), + orCommon.ToGethAddress(order.MakerToken), + orCommon.ToGethAddress(order.TakerToken), + orCommon.ToGethAddress(order.FeeRecipient)} + + // Set the order values + makerTokenAmount, _ := new(big.Int).SetString(order.MakerTokenAmount.String(), 10) + takerTokenAmount, _ := new(big.Int).SetString(order.TakerTokenAmount.String(), 10) + makerFee, _ := new(big.Int).SetString(order.MakerFee.String(), 10) + takerFee, _ := new(big.Int).SetString(order.TakerFee.String(), 10) + expirationTime, _ := new(big.Int).SetString(order.ExpirationTimestampInSec.String(), 10) + salt, _ := new(big.Int).SetString(order.Salt.String(), 10) + orderValues := [6]*big.Int{ + makerTokenAmount, + takerTokenAmount, + makerFee, + takerFee, + expirationTime, + salt} + + // Fill the order + fillTransaction, err := exchange.FillOrder( + transactOpt, + orderAddresses, + orderValues, + takerValue, + true, + order.Signature.V, + order.Signature.R, + order.Signature.S) + if err != nil { + log.Printf(err.Error()) + return subcommands.ExitFailure + } + _, err = bind.WaitMined(context.Background(), conn, fillTransaction) + if err != nil { + log.Printf(err.Error()) + return subcommands.ExitFailure + } + } + return subcommands.ExitSuccess +} diff --git a/zeroEx/query.go b/zeroEx/query.go new file mode 100644 index 0000000..48216ed --- /dev/null +++ b/zeroEx/query.go @@ -0,0 +1,119 @@ +package zeroEx + +import ( + "os" + "flag" + "context" + "github.com/google/subcommands" + "github.com/notegio/massive/utils" + "io" + "strings" + "fmt" + "log" + "net/http" + "encoding/json" + "io/ioutil" +) + +type queryOrders struct { + targetURL string + inputFileName string + outputFileName string + makerToken string + takerToken string + exchange string + inputFile *os.File + outputFile *os.File +} + +type ecSignature struct { + V int64 `json:"v"` + R string `json:"r"` + S string `json:"s"` +} + +type OrderResponse struct { + Exchange string `json:"exchangeContractAddress"` + Maker string `json:"maker"` + Taker string `json:"taker"` + MakerToken string `json:"makerTokenAddress"` + TakerToken string `json:"takerTokenAddress"` + FeeRecipient string `json:"feeRecipient"` + MakerTokenAmount string `json:"makerTokenAmount"` + TakerTokenAmount string `json:"takerTokenAmount"` + MakerFee string `json:"makerFee"` + TakerFee string `json:"takerFee"` + Expiration string `json:"expirationUnixTimestampSec"` + Salt string `json:"salt"` + Signature ecSignature `json:"ecSignature"` +} + +type Orders struct { + orders []OrderResponse +} + + + +func (p *queryOrders) FileNames() (string, string) { + return p.inputFileName, p.outputFileName +} + +func (p *queryOrders) SetIOFiles(inputFile, outputFile *os.File) { + p.inputFile, p.outputFile = inputFile, outputFile +} + +func (*queryOrders) Name() string { return "query" } +func (*queryOrders) Synopsis() string { return "Query the relayer api for orders" } +func (*queryOrders) Usage() string { + return `msv 0x query [--target RELAYER_URL] [--maker-token 0x..] [--taker-token 0x..] [--exchange testrpc] [--input FILE] [--output FILE]: + Get fees from the target relayer and set them on the order +` +} + +func (p *queryOrders) SetFlags(f *flag.FlagSet) { + f.StringVar(&p.targetURL, "target", "https://api.openrelay.xyz", "Set the target 0x relayer") + f.StringVar(&p.makerToken, "maker-token", "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c", "The maker token contract address") + f.StringVar(&p.takerToken, "taker-token", "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401", "The taker token contract address") + f.StringVar(&p.exchange, "exchange", "0x48bacb9266a570d521063ef5dd96e61686dbe788", "The exchange contract address") + f.StringVar(&p.inputFileName, "input", "", "Input file [stdin]") + f.StringVar(&p.outputFileName, "output", "", "Output file [stdout]") +} + + +func (p *queryOrders) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { + if f.NArg() != 0 { + os.Stderr.WriteString(p.Usage()) + return subcommands.ExitUsageError + } + utils.SetIO(p) + return QueryMain(p.targetURL, p.inputFile, p.outputFile, p.makerToken, p.takerToken, p.exchange) +} + +func QueryMain(targetURL string, inputFile io.Reader, outputFile io.Writer, makerToken string, takerToken string, exchange string) subcommands.ExitStatus { + + targetURL = strings.TrimSuffix(targetURL, "/") + resp, err := http.Get(fmt.Sprintf("%v/v0/orders?makerTokenAddress=%v&takerTokenAddress=%v&exchangeContractAddress=%v", targetURL, makerToken, takerToken, exchange)) + if err != nil { + log.Printf("Getting orders from %v: %v", targetURL, err.Error()) + return subcommands.ExitFailure + } + orderBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Printf("Error getting response body: %v", err.Error()) + return subcommands.ExitFailure + } + if resp.StatusCode != 200 { + log.Printf("Got unexpected status code: %v", resp.StatusCode) + log.Printf("Body: %v", string(orderBytes)) + return subcommands.ExitFailure + } + orders := make([]OrderResponse,0) + if err := json.Unmarshal(orderBytes, &orders); err != nil { + log.Printf("Error parsing response body: %v - '%v'", err.Error(), string(orderBytes)) + return subcommands.ExitFailure + } + for _,order := range orders { + utils.WriteRecord(order, outputFile) + } + return subcommands.ExitSuccess +} diff --git a/zeroEx/zeroEx.go b/zeroEx/zeroEx.go index 095b2dd..bf2bcb6 100644 --- a/zeroEx/zeroEx.go +++ b/zeroEx/zeroEx.go @@ -31,6 +31,8 @@ func (p *ZeroExCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} commander.Register(&csvReader{}, "") commander.Register(&setExchange{}, "") commander.Register(&setAllowance{}, "") + commander.Register(&queryOrders{}, "") + commander.Register(&fillOrder{}, "") commander.Register(commander.HelpCommand(), "") commander.Register(commander.FlagsCommand(), "") commander.Register(commander.CommandsCommand(), "")