diff --git a/ui/rootui.go b/ui/rootui.go index 7509375..d8d9027 100644 --- a/ui/rootui.go +++ b/ui/rootui.go @@ -13,13 +13,14 @@ func init() { ApiKeyItem.Value = state.State.AlchApiKey } +var SettingsItem = &Item{Label: settingsIcon + " Settings", Details: "Paymasters, Signers, ChainID, ..."} +var UserOpItem = &Item{Label: userOpsIcon + " User Operations", Details: "Manage User Operations"} +var AbisItem = &Item{Label: abisIcon + " ABIs", Details: "Manage ABIs"} + var PaymasterItem = &Item{Label: "Paymaster", Details: "Manage Paymaster settings"} -var UserOpItem = &Item{Label: "User Operations", Details: "Manage User Operations"} -var AbisItem = &Item{Label: "ABIs", Details: "Manage ABIs"} var SignerItem = &Item{Label: "Signer", Details: "Manage Signer settings"} var EntryPointItem = &Item{Label: "Entrypoint", Details: "Set Entrypoint"} var ApiKeyItem = &Item{Label: "Alchemy API Key", Details: "Set Alchemy API Key"} -var SettingsItem = &Item{Label: "Settings", Details: "Paymasters, Signers, ChainID, ..."} func RootUI() { items := []*Item{ diff --git a/ui/signui.go b/ui/signui.go index 40fb903..136d1d0 100644 --- a/ui/signui.go +++ b/ui/signui.go @@ -26,7 +26,7 @@ var PreHashV7Item = &Item{Label: "Pre Hash_v7", Details: "Hash of an encoded use var PreHashV6Item = &Item{Label: "Pre Hash_v6", Details: "Hash of an encoded user operation"} var EncodedBytesItem = &Item{Label: "Encoded Bytes", Details: "Encoded bytes of the user operation"} -func GetHashUI(usop *userop.UserOperation) (sig []byte, err error) { +func UtilsUI(usop *userop.UserOperation) (sig []byte, err error) { var SignItem = &Item{Label: "Sign", Details: "Sign the user operation"} prompt := promptui.Select{ Label: "Select an option", @@ -76,7 +76,6 @@ func GetHashUI(usop *userop.UserOperation) (sig []byte, err error) { hash, err = userop.GetUserOpHashV6(usop, EntryPoint, ChainID) fmt.Println("Signing using v6 hashes") } else { - hash, err = userop.GetUserOpHashV7(usop.Pack(), EntryPoint, ChainID) fmt.Println("Signing using v7 hashes") } @@ -160,7 +159,7 @@ func SetSignatureUI(userop *userop.UserOperation) (calldata []byte, err error) { } return it.Value.([]byte), err case UseSignerItem.Label: - return GetHashUI(userop) + return UtilsUI(userop) default: fmt.Println("Unreachable reached:", sel) } diff --git a/ui/uitems.go b/ui/uitems.go index 78bd878..d00cded 100644 --- a/ui/uitems.go +++ b/ui/uitems.go @@ -15,7 +15,8 @@ type Item struct { Label string Value interface{} Details string - DisplayValueString string //could be a function, but I am lazy + DisplayValueString string // could be a function, but I am lazy + IsUserOp bool // To show them in a different color now that there are less menus } func (i *Item) DisplayValue() string { @@ -89,12 +90,16 @@ func (i *Item) String() string { const unicorn = "\U0001F984" +const settingsIcon = "\U0001F6E0" +const userOpsIcon = "\U0001F464" +const abisIcon = "\U0001F517" + const ( EXIT = "EXIT" BACK = "BACK" ) -// Rewrite the above as variable instantiation witt OK=&Item{Label: "OK"} pattern +// Rewrite the above as variable instantiation with OK=&Item{Label: "OK"} pattern var OK = &Item{Label: "OK", Details: "Confirm and proceed"} var Back = &Item{Label: BACK, Details: "Go back to previous menu"} var Exit = &Item{Label: EXIT, Details: "Exit the program"} @@ -102,8 +107,8 @@ var Set = &Item{Label: "Set", Details: "Set the value"} var ItemTemplate = &promptui.SelectTemplates{ Label: "{{ . | bold | cyan}}", - Inactive: `{{if eq .Label "BACK"}}{{.Label | yellow}}{{else if eq .Label "EXIT"}}{{.Label | red}}{{else if eq .Label "Set"}}{{.Label | green}}{{else}}{{ .Label }}{{with .DisplayValue}}: {{.}}{{end}}{{end}}`, - Active: `{{if eq .Label "BACK"}}{{.Label | yellow | bold | underline}}{{else if eq .Label "EXIT"}}{{.Label | red | bold | underline}}{{else if eq .Label "Set"}}{{.Label | green | bold | underline}}{{else}}{{ .Label | bold | underline }}{{with .DisplayValue}}: {{. | bold}}{{end}}{{end}}`, + Inactive: `{{if eq .IsUserOp true}}{{.Label | magenta}}{{else if eq .Label "BACK"}}{{.Label | yellow}}{{else if eq .Label "EXIT"}}{{.Label | red}}{{else if or (eq .Label "Set") (eq .Label "Export User Operation")}}{{.Label | green}}{{else if eq .Label "Utils: hashes and signatures"}}{{.Label | faint}}{{else}}{{ .Label }}{{with .DisplayValue}}: {{.}}{{end}}{{end}}`, + Active: `{{if eq .IsUserOp true}}{{.Label | magenta | bold | underline}}{{else if eq .Label "BACK"}}{{.Label | yellow | bold | underline}}{{else if eq .Label "EXIT"}}{{.Label | red | bold | underline}}{{else if or (eq .Label "Set") (eq .Label "Export User Operation")}}{{.Label | green | bold | underline}}{{else if eq .Label "Utils: hashes and signatures"}}{{.Label | faint | bold | underline}}{{else}}{{ .Label | bold | underline }}{{with .DisplayValue}}: {{. | bold}}{{end}}{{end}}`, Selected: "{{. | faint}}", Details: "{{ .Details | faint }}", } diff --git a/ui/useropui.go b/ui/useropui.go index 00224b3..054d212 100644 --- a/ui/useropui.go +++ b/ui/useropui.go @@ -16,35 +16,12 @@ import ( var SelectUserOpItem = &Item{Label: "Select User Operation", Details: "Select a user operation"} var CreateUserOpItem = &Item{Label: "Create User Operation", Details: "Create a new user operation"} var CloneUserOpItem = &Item{Label: "Clone User Operation", Details: "Clone a user operation"} +var DeleteUserOpItem = &Item{Label: "Delete User Operation", Details: "Delete a user operation"} func TopUserOpUI(callbackItem *Item) { - - usOpItem := &Item{} - workItem := &Item{} - deleteItem := &Item{} for { - items := []*Item{} - if usOpItem.Value != nil { - if usop, ok := usOpItem.Value.(*userop.UserOperation); ok { - if callbackItem != nil { - callbackItem.Label = "Select this UserOperation" - callbackItem.Value = usop - items = append(items, callbackItem) - } - - workItem = &Item{Label: "Work on User Operation: " + usOpItem.Label, Details: fmt.Sprintf("%s/%v", usop.Sender, usop.Nonce)} - deleteItem = &Item{Label: "Delete User Operation: " + usOpItem.Label, Details: "Delete this user operation"} - items = append(items, workItem, deleteItem) - - } - } - items = append(items, []*Item{ - SelectUserOpItem, - CreateUserOpItem, - CloneUserOpItem, - }...) - //Select a userOp, create a new one, or go back - + userOpItems := GetUserOpItems() + items := append(userOpItems, []*Item{CreateUserOpItem, CloneUserOpItem, DeleteUserOpItem}...) items = append(items, Back) // Create a new select prompt @@ -52,7 +29,7 @@ func TopUserOpUI(callbackItem *Item) { Label: "Select an option", Items: items, Templates: ItemTemplate, - Size: 10, + Size: len(items), } _, sel, err := prompt.Run() if err != nil { @@ -61,30 +38,19 @@ func TopUserOpUI(callbackItem *Item) { switch sel { case Back.Label: return - case SelectUserOpItem.Label: - - SelectUserOpUI(usOpItem) case CreateUserOpItem.Label: - CreateUserOpUI(usOpItem) + CreateUserOpUI() case CloneUserOpItem.Label: - CloneUserOpUI(usOpItem) - case workItem.Label: - usop := usOpItem.Value.(*userop.UserOperation) //Has been checked when generating ui, and there should be no concurrency, so it is safe - UserOpUI(usop) - case deleteItem.Label: - delete(state.State.UserOps, usOpItem.Label) - state.State.Save() - return - case callbackItem.Label: - return + CloneUserOpUI() + case DeleteUserOpItem.Label: + DeleteUserOpUI() default: - fmt.Println("Not implemented yet:", sel) + UserOpContentUI(state.State.UserOps[sel]) } } - } -func CloneUserOpUI(topIt *Item) { +func CloneUserOpUI() { it := &Item{} SelectUserOpUI(it) if it.Value == nil { @@ -121,35 +87,31 @@ func CloneUserOpUI(topIt *Item) { fmt.Printf("Error cloning UserOp: %v\n", err) return } - - topIt.Value = clone - topIt.Label = newname state.State.UserOps[newname] = clone.(*userop.UserOperation) state.State.Save() } -func SelectUserOpUI(topit *Item) { - items := []*Item{} - keys := make([]string, 0, len(state.State.UserOps)) - for k := range state.State.UserOps { - keys = append(keys, k) - } - if len(keys) == 0 { - fmt.Println("No UserOps available") +func DeleteUserOpUI() { + it := &Item{} + SelectUserOpUI(it) + if it.Value == nil { + fmt.Println("Nothing to delete") return } - sort.Strings(keys) - for _, name := range keys { - uop := state.State.UserOps[name] - items = append(items, &Item{Label: name, Details: fmt.Sprintf("Sender: %s, Nonce: %d", uop.Sender, uop.Nonce)}) - } - items = append(items, Back) + delete(state.State.UserOps, it.Label) + state.State.Save() +} + +func SelectUserOpUI(topit *Item) { + userOpItems := GetUserOpItems() + items := append(userOpItems, Back) + // Create a new select prompt prompt := promptui.Select{ Label: "Select UserOperation", Items: items, Templates: ItemTemplate, - Size: 10, + Size: len(items), } _, sel, err := prompt.Run() if err != nil { @@ -164,7 +126,25 @@ func SelectUserOpUI(topit *Item) { } -func CreateUserOpUI(topIt *Item) { +func GetUserOpItems() []*Item { + items := []*Item{} + keys := make([]string, 0, len(state.State.UserOps)) + for k := range state.State.UserOps { + keys = append(keys, k) + } + if len(keys) == 0 { + fmt.Println("No UserOps available") + return items + } + sort.Strings(keys) + for _, name := range keys { + uop := state.State.UserOps[name] + items = append(items, &Item{Label: name, Details: fmt.Sprintf("Sender: %s, Nonce: %d", uop.Sender, uop.Nonce), IsUserOp: true}) + } + return items +} + +func CreateUserOpUI() { //prompt for name prompt := promptui.Prompt{ Label: "Enter UserOp Name", @@ -185,21 +165,18 @@ func CreateUserOpUI(topIt *Item) { fmt.Println(err) return } - topIt.Label = name - topIt.Value = nuop - UserOpContentUI(topIt) - + UserOpContentUI(nuop) } var UserOpContentItem = &Item{Label: "User Operation Content", Details: "Manage user operation content"} var ExportUserOpItem = &Item{Label: "Export User Operation", Details: "Select the export format"} -var GetHashItem = &Item{Label: "Hashes and signatures", Details: "Get the hash of the user operation with entrypoint and chainid"} +var UtilsItem = &Item{Label: "Utils: hashes and signatures", Details: "Get the hash of the user operation with entrypoint and chainid"} func UserOpUI(usop *userop.UserOperation) { items := []*Item{ UserOpContentItem, ExportUserOpItem, - GetHashItem, + UtilsItem, Back, } // Create a new select prompt @@ -218,12 +195,12 @@ func UserOpUI(usop *userop.UserOperation) { case Back.Label: return case UserOpContentItem.Label: - it := &Item{Value: usop} - UserOpContentUI(it) + // it := &Item{Value: usop} + UserOpContentUI(usop) case ExportUserOpItem.Label: ExportUserOpUI(usop) - case GetHashItem.Label: - GetHashUI(usop) + case UtilsItem.Label: + UtilsUI(usop) default: fmt.Println("Not implemented yet:", sel) } @@ -248,12 +225,8 @@ var PaymasterVerificationGasLimitItem = &Item{Label: "Paymaster Verification Gas var PaymasterPostOpGasLimitItem = &Item{Label: "Paymaster Post Op Gas Limit", Details: "Set Paymaster Post Op Gas Limit", Value: userop.DefaultPaymasterPostOpGasLimit} var SignatureItem = &Item{Label: "Signature", Details: "Set Signature"} -func UserOpContentUI(topIt *Item) { - var usop *userop.UserOperation - - ok := false - usop, ok = topIt.Value.(*userop.UserOperation) - if !ok || usop == nil { +func UserOpContentUI(usop *userop.UserOperation) { + if usop == nil { fmt.Println("Invalid UserOp passed to UserOpContentUI") return } @@ -274,6 +247,8 @@ func UserOpContentUI(topIt *Item) { PaymasterVerificationGasLimitItem, PaymasterPostOpGasLimitItem, SignatureItem, + ExportUserOpItem, + UtilsItem, Back, } copyFromUseropToItems(usop) @@ -282,7 +257,7 @@ func UserOpContentUI(topIt *Item) { Label: "Select an option", Items: items, Templates: ItemTemplate, - Size: 22, + Size: len(items), } for { _, sel, err := prompt.Run() @@ -292,7 +267,7 @@ func UserOpContentUI(topIt *Item) { switch sel { case Back.Label: copyValuesToUserOp(usop) - topIt.Value = usop + //topIt.Value = usop return case NonceItem.Label, CallGasLimitItem.Label, VerificationGasLimitItem.Label, PreVerificationGasItem.Label, MaxFeePerGasItem.Label, MaxPriorityFeePerGasItem.Label, @@ -337,11 +312,13 @@ func UserOpContentUI(topIt *Item) { it, _ := GetItem(sel, items) addr, ok := AddressFromBookUI(sel) if ok { - it.Value = addr usop.Sender = SenderItem.Value.(*common.Address) - } + case ExportUserOpItem.Label: + ExportUserOpUI(usop) + case UtilsItem.Label: + UtilsUI(usop) default: fmt.Println("Not implemented yet:", sel) } @@ -439,6 +416,7 @@ func ExportUserOpUI(uop *userop.UserOperation) { default: fmt.Println("Not implemented yet:", sel) } + // return } }