From b27ab720d9c2e289c64ab73f842ba5fe1d58e79a Mon Sep 17 00:00:00 2001 From: Ben Lebherz Date: Tue, 25 Jul 2023 17:37:53 +0200 Subject: [PATCH] add gas settings and fix signing in manifold minter --- cmd/mintcmd/manifold.go | 180 +++++++++++++++++++++++++++++++++------- go.mod | 5 +- go.sum | 3 + 3 files changed, 156 insertions(+), 32 deletions(-) diff --git a/cmd/mintcmd/manifold.go b/cmd/mintcmd/manifold.go index 9c0a61a..fa70db9 100644 --- a/cmd/mintcmd/manifold.go +++ b/cmd/mintcmd/manifold.go @@ -102,7 +102,7 @@ func mintManifold(_ *cobra.Command, _ []string) { rpcClients := mapset.NewSet[*ethclient.Client]() rpcEndpoints := mapset.NewSet[string]() - availableWallets := mapset.NewSet[*MintWallet]() + availableWallets := make([]*MintWallet, 0) mintWallets := mapset.NewSet[*MintWallet]() // check for valid keys @@ -129,7 +129,7 @@ func mintManifold(_ *cobra.Command, _ []string) { mintWallet.color = style.GenerateColorWithSeed(mintWallet.address.Hash().Big().Int64()) mintWallet.tag = lipgloss.NewStyle().Foreground(mintWallet.color).Render(style.ShortenAddress(mintWallet.address)) - availableWallets.Add(mintWallet) + availableWallets = append(availableWallets, mintWallet) } // connect to rpc endpoints @@ -144,13 +144,15 @@ func mintManifold(_ *cobra.Command, _ []string) { rpcClients.Add(rpcClient) } - mintIdentifier, err := getMintIdentifier("https://app.manifold.xyz/c/above-the-noise") + mintIdentifier, err := getMintIdentifier(flagURL) if err != nil { log.Fatalf("โŒ getting mint identifier from manifold failed: %v", err) return } + log.Print("mintIdentifier: %sd", mintIdentifier) + mintInfo, err := getMintInfoWithURL(flagURL) if err != nil { log.Fatalf("โŒ getting mint identifier from manifold failed: %v", err) @@ -158,6 +160,15 @@ func mintManifold(_ *cobra.Command, _ []string) { return } + getMintInfoWithIdentifier, err := getMintInfoWithIdentifier(mintIdentifier) + if err != nil { + log.Fatalf("โŒ getting mint identifier from manifold failed: %v", err) + + return + } + + log.Debug(getMintInfoWithIdentifier) + manifoldInstanceID := *big.NewInt(int64(mintInfo.PublicData.ClaimIndex)) if mintInfo.PublicData.ExtensionContractAddress != internal.ManifoldLazyClaimERC1155 { @@ -178,7 +189,7 @@ func mintManifold(_ *cobra.Command, _ []string) { log.Print("") fmtWallets := make([]string, 0) - for _, wallet := range availableWallets.ToSlice() { + for _, wallet := range availableWallets { fmtWallets = append(fmtWallets, style.Bold(wallet.tag)) } @@ -188,14 +199,11 @@ func mintManifold(_ *cobra.Command, _ []string) { // randomly choose numWallets from our available wallets // (max) number of wallets to use - numWallets := uint16(math.Min(float64(viper.GetUint16("mint.manifold.num-wallets")), float64(availableWallets.Cardinality()))) + numWallets := uint16(math.Min(float64(viper.GetUint16("mint.manifold.num-wallets")), float64(len(availableWallets)))) - // choose unique numWallets random wallets - for i := uint16(0); i < numWallets; i++ { - // choose a random wallet - if wallet, ok := availableWallets.Pop(); ok && wallet != nil { - mintWallets.Add(wallet) - } + // select the first numWallets from our available wallets + for _, wallet := range availableWallets[:numWallets] { + mintWallets.Add(wallet) } fmtWallets = make([]string, 0) @@ -309,7 +317,7 @@ func mintManifold(_ *cobra.Command, _ []string) { wg.Wait() log.Print("") - log.Print(" ๐ŸŸข all jobs finished! ๐Ÿน") + log.Print(" ๐Ÿน all jobs finished! ๐Ÿน") log.Print("") } @@ -321,10 +329,10 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer rpcIdx := rand.Intn(len(rpcEndpoints.ToSlice())) //nolint:gosec rpcEndpoint := rpcEndpoints.ToSlice()[rpcIdx] - log.Debugf("%s | rpc endpoints (%d): %s", mintWallet.tag, rpcEndpoints.Cardinality(), style.BoldAlmostWhite(fmt.Sprintf("%+v", rpcEndpoints))) - - log.Printf("%s | selected rpc endpoint: %s", mintWallet.tag, style.BoldAlmostWhite(fmt.Sprint(rpcIdx))) + log.Debugf("%s | ๐Ÿ“‘ rpc endpoints (%d): %s", mintWallet.tag, rpcEndpoints.Cardinality(), style.BoldAlmostWhite(fmt.Sprintf("%+v", rpcEndpoints))) + log.Debugf("%s | ๐ŸŽฏ selected rpc endpoint: %s", mintWallet.tag, style.BoldAlmostWhite(fmt.Sprint(rpcIdx))) + // connect to rpc endpoint rpcClient, err := ethclient.Dial(rpcEndpoint) if err != nil { log.Errorf("โŒ failed to connect to rpc endpoint %s: %v", rpcEndpoint, err) @@ -332,7 +340,8 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer continue } - log.Printf("%s | preparing transaction...", mintWallet.tag) + // contract binding + log.Printf("%s | create contract binding...", mintWallet.tag) lazyClaimERC1155, err := manifoldABIs.NewLazyClaimERC1155(internal.ManifoldLazyClaimERC1155, rpcClient) if err != nil { @@ -341,6 +350,8 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer continue } + log.Debugf("%s | lazyClaimERC1155: %+v", mintWallet.tag, style.BoldAlmostWhite(fmt.Sprint(lazyClaimERC1155))) + // get the nonce nonce, err := rpcClient.PendingNonceAt(context.Background(), crypto.PubkeyToAddress(mintWallet.privateKey.PublicKey)) if err != nil { @@ -349,9 +360,50 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer continue } + log.Debugf("%s | nonce: %+v", mintWallet.tag, style.BoldAlmostWhite(fmt.Sprint(nonce))) + + // get the current gas price + gasPrice, err := rpcClient.SuggestGasPrice(context.Background()) + if err != nil { + log.Errorf("%s | โŒ getting gasPrice failed: %+v", mintWallet.tag, style.BoldAlmostWhite(err.Error())) + + continue + } + + log.Debugf("%s | โ›ฝ๏ธ gasPrice: %+v", mintWallet.tag, style.BoldAlmostWhite(fmt.Sprint(gasPrice))) + + // get the current gas tip + gasTip, err := rpcClient.SuggestGasTipCap(context.Background()) + if err != nil { + log.Errorf("%s | โŒ getting gasTip failed: %+v", mintWallet.tag, style.BoldAlmostWhite(err.Error())) + + continue + } + + log.Debugf("%s | โ›ฝ๏ธ gasTip: %+v", mintWallet.tag, style.BoldAlmostWhite(fmt.Sprint(gasTip))) + mintCost := utils.EtherToWei(big.NewFloat(mintInfo.MintPrice)) totalCost := new(big.Int).Add(manifoldFee, mintCost) + // + // create the transaction options + txOpts, err := bind.NewKeyedTransactorWithChainID(mintWallet.privateKey, big.NewInt(1)) + if err != nil { + log.Errorf("%s | โŒ creating transaction options failed: %+v", mintWallet.tag, style.BoldAlmostWhite(err.Error())) + + continue + } + + txOpts.From = crypto.PubkeyToAddress(mintWallet.privateKey.PublicKey) + txOpts.Nonce = big.NewInt(int64(nonce)) + txOpts.Value = totalCost + // use 1.5x the amount of the current suggested gas price + txOpts.GasPrice = new(big.Int).Div(new(big.Int).Mul(gasPrice, big.NewInt(3)), big.NewInt(2)) + // use 2x the amount of the current suggested gas tip + txOpts.GasTipCap = new(big.Int).Mul(gasTip, big.NewInt(2)) + + log.Debugf("%s | txOpts: %#v", mintWallet.tag, txOpts) + // create the transaction var tx *types.Transaction @@ -364,13 +416,9 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer merkelProofs = append(merkelProofs, [][32]byte{claimInfo.MerkleRoot}) } - tx, err = lazyClaimERC1155.MintBatch(&bind.TransactOpts{ - From: crypto.PubkeyToAddress(mintWallet.privateKey.PublicKey), - Nonce: big.NewInt(int64(nonce)), - Value: totalCost, - }, mintInfo.PublicData.CreatorContractAddress, manifoldInstanceID, amountPerTx, mintIndices, merkelProofs, *mintWallet.address) + tx, err = lazyClaimERC1155.MintBatch(txOpts, mintInfo.PublicData.CreatorContractAddress, manifoldInstanceID, amountPerTx, mintIndices, merkelProofs, *mintWallet.address) if err != nil { - log.Printf("%s | โŒ creating transaction failed: %+v", mintWallet.tag, style.BoldAlmostWhite(err.Error())) + log.Printf("%s | โŒ creating batch transaction failed: %+v", mintWallet.tag, style.BoldAlmostWhite(err.Error())) if !viper.GetBool("dev.mode") { continue @@ -397,7 +445,7 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer log.Debugf("%s | tx: %#v", mintWallet.tag, tx) - log.Printf("%s | signing transaction...", mintWallet.tag) + log.Printf("%s | โœ๏ธ signing transaction...", mintWallet.tag) // sign the transaction signedTx, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(1)), mintWallet.privateKey) @@ -407,16 +455,16 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer continue } - log.Debugf("%s | signedTx: %#v", mintWallet.tag, signedTx) + log.Debugf("%s | โœ๏ธ signedTx: %#v", mintWallet.tag, signedTx) // send the transaction - if viper.GetBool("dev.mode") { - log.Printf("%s | would send transaction...", mintWallet.tag) + // if viper.GetBool("dev.mode") { + // log.Printf("%s | would send transaction...", mintWallet.tag) - continue - } + // continue + // } - log.Printf("%s | sending transaction...", mintWallet.tag) + log.Printf("%s | ๐Ÿ“ฆ sending transaction...", mintWallet.tag) err = rpcClient.SendTransaction(context.Background(), signedTx) if err != nil { @@ -450,11 +498,71 @@ func mintERC1155(rpcEndpoints mapset.Set[string], mintWallet *MintWallet, txsPer } if txConfirmed >= int(txsPerWallet) { - log.Printf("%s | all txs confirmed! ๐Ÿน", mintWallet.tag) + log.Printf("%s | ๐Ÿ’ฅ ๐Ÿ™Œ ๐Ÿ’ฅ all txs confirmed! ๐Ÿน ๐Ÿฅƒ ๐Ÿฅ‚s", mintWallet.tag) return } + + time.Sleep(time.Millisecond * 337) + } +} + +func getMintInfoWithIdentifier(identifier int64) (*manifold.DataResponse, error) { + url := fmt.Sprintf("https://apps.api.manifoldxyz.dev/public/instance/data?id=%d", identifier) + + log.Printf("Identifier url: %s", url) + + response, err := utils.HTTP.GetWithTLS12(context.TODO(), url) + if err != nil { + if os.IsTimeout(err) { + log.Printf("โŒ›๏ธ Identifier GetMintInfo ยท timeout while fetching: %+v\n", err.Error()) + } else { + log.Errorf("โŒ Identifier gGetMintInfo ยท error: %+v\n", err.Error()) + } + + return nil, err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + log.Errorf("โŒ Identifier gGetMintInfo ยท error: %+v\n", response.Status) + + return nil, err + } + + // read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + log.Errorf("โŒ Identifier gGetMintInfo ยท response read error: %+v\n", err.Error()) + + return nil, err + } + + // decode the data + if err != nil || !json.Valid(responseBody) { + log.Warnf("getContractMetadata invalid json: %s", err) + + return nil, err } + + var unmarshalled map[string]interface{} + _ = json.Unmarshal(responseBody, &unmarshalled) + + log.Print("") + log.Print("") + log.Print("") + log.Print("with identifier") + pretty.Println(unmarshalled) + + // fmt.Println(string(responseBody)) + var decoded *manifold.DataResponse + if err := json.NewDecoder(bytes.NewReader(responseBody)).Decode(&decoded); err != nil { + log.Errorf("โŒ decode error: %s\n", err.Error()) + + return nil, err + } + + return decoded, nil } func getMintInfoWithURL(mintURL string) (*manifold.DataResponse, error) { @@ -462,6 +570,9 @@ func getMintInfoWithURL(mintURL string) (*manifold.DataResponse, error) { slug := mintURL[strings.LastIndex(mintURL, "/")+1:] url := fmt.Sprintf("https://apps.api.manifoldxyz.dev/public/instance/data?appId=%d&instanceSlug=%s", manifoldMagicAppID, slug) + + log.Printf("URL url: %s", url) + response, err := utils.HTTP.GetWithTLS12(context.TODO(), url) if err != nil { if os.IsTimeout(err) { @@ -495,6 +606,15 @@ func getMintInfoWithURL(mintURL string) (*manifold.DataResponse, error) { return nil, err } + var unmarshalled map[string]interface{} + _ = json.Unmarshal(responseBody, &unmarshalled) + + log.Print("") + log.Print("") + log.Print("") + log.Print("with URL") + pretty.Println(unmarshalled) + // fmt.Println(string(responseBody)) var decoded *manifold.DataResponse if err := json.NewDecoder(bytes.NewReader(responseBody)).Decode(&decoded); err != nil { diff --git a/go.mod b/go.mod index 5dae490..58af46d 100644 --- a/go.mod +++ b/go.mod @@ -30,10 +30,9 @@ require ( golang.org/x/text v0.11.0 gonum.org/v1/gonum v0.13.0 google.golang.org/grpc v1.56.2 + gotest.tools v2.2.0+incompatible ) -require github.com/google/uuid v1.3.0 // indirect - require ( github.com/DataDog/zstd v1.5.5 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect @@ -59,6 +58,8 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect diff --git a/go.sum b/go.sum index 9511588..8b0512c 100644 --- a/go.sum +++ b/go.sum @@ -220,6 +220,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -936,6 +937,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=