// createSimulationWallet is intended to be called from the rpcclient // and used to create a wallet for actors involved in simulations. func createSimulationWallet(cfg *config) error { // Simulation wallet password is 'password'. privPass := []byte("password") // Public passphrase is the default. pubPass := []byte(wallet.InsecurePubPassphrase) netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params) // Create the wallet. dbPath := filepath.Join(netDir, walletDbName) fmt.Println("Creating the wallet...") // Create the wallet database backed by bolt db. db, err := walletdb.Create("bdb", dbPath) if err != nil { return err } defer db.Close() // Create the wallet. err = wallet.Create(db, pubPass, privPass, nil, activeNet.Params) if err != nil { return err } fmt.Println("The wallet has been created successfully.") return nil }
func testStore() (*Store, func(), error) { tmpDir, err := ioutil.TempDir("", "wtxmgr_test") if err != nil { return nil, func() {}, err } db, err := walletdb.Create("bdb", filepath.Join(tmpDir, "db")) if err != nil { teardown := func() { os.RemoveAll(tmpDir) } return nil, teardown, err } teardown := func() { db.Close() os.RemoveAll(tmpDir) } ns, err := db.Namespace([]byte("txstore")) if err != nil { return nil, teardown, err } err = Create(ns) if err != nil { return nil, teardown, err } s, err := Open(ns, &chaincfg.TestNet3Params) return s, teardown, err }
func testDB() (walletdb.DB, func(), error) { tmpDir, err := ioutil.TempDir("", "wtxmgr_test") if err != nil { return nil, func() {}, err } db, err := walletdb.Create("bdb", filepath.Join(tmpDir, "db")) return db, func() { os.RemoveAll(tmpDir) }, err }
// TestInterface performs all interfaces tests for this database driver. func TestInterface(t *testing.T) { // Create a new database to run tests against. dbPath := "interfacetest.db" db, err := walletdb.Create(dbType, dbPath) if err != nil { t.Errorf("Failed to create test database (%s) %v", dbType, err) return } defer os.Remove(dbPath) defer db.Close() // Run all of the interface tests against the database. testInterface(t, db) }
// createDbNamespace creates a new wallet database at the provided path and // returns it along with the address manager namespace. func createDbNamespace(dbPath string) (walletdb.DB, walletdb.Namespace, error) { db, err := walletdb.Create("bdb", dbPath) if err != nil { return nil, nil, err } namespace, err := db.Namespace(waddrmgrNamespaceKey) if err != nil { db.Close() return nil, nil, err } return db, namespace, nil }
func createWalletDB() (walletdb.DB, func(), error) { dir, err := ioutil.TempDir("", "votingpool_example") if err != nil { return nil, nil, err } db, err := walletdb.Create("bdb", filepath.Join(dir, "wallet.db")) if err != nil { return nil, nil, err } dbTearDown := func() { db.Close() os.RemoveAll(dir) } return db, dbTearDown, nil }
// exampleLoadDB is used in the examples to elide the setup code. func exampleLoadDB() (walletdb.DB, func(), error) { dbName := fmt.Sprintf("exampleload%d.db", exampleNum) dbPath := filepath.Join(os.TempDir(), dbName) db, err := walletdb.Create("bdb", dbPath) if err != nil { return nil, nil, err } teardownFunc := func() { db.Close() os.Remove(dbPath) } exampleNum++ return db, teardownFunc, err }
// createDbNamespace creates a new wallet database at the provided path and // returns it along with the address manager namespace. func createDbNamespace(dbPath string) (walletdb.DB, walletdb.Namespace, error) { db, err := walletdb.Create("bdb", dbPath) if err != nil { fmt.Println("fuk") return nil, nil, err } namespace, err := db.Namespace([]byte("waddr")) if err != nil { db.Close() return nil, nil, err } return db, namespace, nil }
// TstCreatePool creates a Pool on a fresh walletdb and returns it. It also // returns the pool's waddrmgr.Manager (which uses the same walletdb, but with a // different namespace) as a convenience, and a teardown function that closes // the Manager and removes the directory used to store the database. func TstCreatePool(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager, pool *Pool) { // This should be moved somewhere else eventually as not all of our tests // call this function, but right now the only option would be to have the // t.Parallel() call in each of our tests. t.Parallel() // Create a new wallet DB and addr manager. dir, err := ioutil.TempDir("", "pool_test") if err != nil { t.Fatalf("Failed to create db dir: %v", err) } db, err := walletdb.Create("bdb", filepath.Join(dir, "wallet.db")) if err != nil { t.Fatalf("Failed to create wallet DB: %v", err) } mgrNamespace, err := db.Namespace([]byte("waddrmgr")) if err != nil { t.Fatalf("Failed to create addr manager DB namespace: %v", err) } var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1} err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase, privPassphrase, &chaincfg.MainNetParams, fastScrypt) if err == nil { mgr, err = waddrmgr.Open(mgrNamespace, pubPassphrase, &chaincfg.MainNetParams, nil) } if err != nil { t.Fatalf("Failed to create addr manager: %v", err) } // Create a walletdb for votingpools. vpNamespace, err := db.Namespace([]byte("votingpool")) if err != nil { t.Fatalf("Failed to create VotingPool DB namespace: %v", err) } pool, err = Create(vpNamespace, mgr, []byte{0x00}) if err != nil { t.Fatalf("Voting Pool creation failed: %v", err) } tearDownFunc = func() { db.Close() mgr.Close() os.RemoveAll(dir) } return tearDownFunc, mgr, pool }
// Create creates a wallet with the specified path, private key password and seed. // Seed can be created using: hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen) func Create(path, privPass string, seed []byte) (*Wallet, error) { db, err := walletdb.Create("bdb", path) if err != nil { return nil, err } namespace, err := db.Namespace(waddrmgrNamespaceKey) if err != nil { return nil, err } manager, err := waddrmgr.Create(namespace, seed, nil, []byte(privPass), bitcoinNetwork.Params, nil) if err != nil { return nil, err } manager.Close() return openWallet(db, privPass, seed) }
// createSimulationWallet is intended to be called from the rpcclient // and used to create a wallet for actors involved in simulations. func createSimulationWallet(cfg *config) error { // Simulation wallet password is 'password'. privPass := []byte("password") // Public passphrase is the default. pubPass := []byte(defaultPubPassphrase) // Generate a random seed. seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen) if err != nil { return err } netDir := networkDir(cfg.DataDir, activeNet.Params) // Create the wallet. dbPath := filepath.Join(netDir, walletDbName) fmt.Println("Creating the wallet...") // Create the wallet database backed by bolt db. db, err := walletdb.Create("bdb", dbPath) if err != nil { return err } defer db.Close() // Create the address manager. waddrmgrNamespace, err := db.Namespace(waddrmgrNamespaceKey) if err != nil { return err } manager, err := waddrmgr.Create(waddrmgrNamespace, seed, []byte(pubPass), []byte(privPass), activeNet.Params, nil) if err != nil { return err } manager.Close() fmt.Println("The wallet has been created successfully.") return nil }
// CreateNewWallet creates a new wallet using the provided public and private // passphrases. The seed is optional. If non-nil, addresses are derived from // this seed. If nil, a secure random seed is generated. func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte) (*Wallet, error) { defer l.mu.Unlock() l.mu.Lock() if l.wallet != nil { return nil, ErrLoaded } dbPath := filepath.Join(l.dbDirPath, walletDbName) exists, err := fileExists(dbPath) if err != nil { return nil, err } if exists { return nil, ErrExists } // Create the wallet database backed by bolt db. err = os.MkdirAll(l.dbDirPath, 0700) if err != nil { return nil, err } db, err := walletdb.Create("bdb", dbPath) if err != nil { return nil, err } // Initialize the newly created database for the wallet before opening. err = Create(db, pubPassphrase, privPassphrase, seed, l.chainParams) if err != nil { return nil, err } // Open the newly-created wallet. w, err := Open(db, pubPassphrase, nil, l.chainParams) if err != nil { return nil, err } w.Start() l.onLoaded(w, db) return w, nil }
func TstCreateTxStore(t *testing.T) (store *wtxmgr.Store, tearDown func()) { dir, err := ioutil.TempDir("", "pool_test_txstore") if err != nil { t.Fatalf("Failed to create txstore dir: %v", err) } db, err := walletdb.Create("bdb", filepath.Join(dir, "txstore.db")) if err != nil { t.Fatalf("Failed to create walletdb: %v", err) } wtxmgrNamespace, err := db.Namespace([]byte("testtxstore")) if err != nil { t.Fatalf("Failed to create walletdb namespace: %v", err) } s, err := wtxmgr.Create(wtxmgrNamespace) if err != nil { t.Fatalf("Failed to create txstore: %v", err) } return s, func() { os.RemoveAll(dir) } }
func exampleCreateTxStore() (*wtxmgr.Store, func(), error) { dir, err := ioutil.TempDir("", "pool_test_txstore") if err != nil { return nil, nil, err } db, err := walletdb.Create("bdb", filepath.Join(dir, "txstore.db")) if err != nil { return nil, nil, err } wtxmgrNamespace, err := db.Namespace([]byte("testtxstore")) if err != nil { return nil, nil, err } s, err := wtxmgr.Create(wtxmgrNamespace) if err != nil { return nil, nil, err } return s, func() { os.RemoveAll(dir) }, nil }
// createWallet generates a new wallet. The new wallet will reside at the // provided path. // TODO(roasbeef): maybe pass in config after all for testing purposes? func createWallet(privPass, pubPass, userSeed []byte, dbPath string) error { // TODO(roasbeef): replace with tadge's seed format? hdSeed := userSeed var seedErr error if userSeed == nil { hdSeed, seedErr = hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen) if seedErr != nil { return seedErr } } // Create the wallet. fmt.Println("Creating the wallet...") // Create the wallet database backed by bolt db. db, err := walletdb.Create("bdb", dbPath) if err != nil { return err } // Create the address manager. namespace, err := db.Namespace(waddrmgrNamespaceKey) if err != nil { return err } manager, err := waddrmgr.Create(namespace, hdSeed, []byte(pubPass), []byte(privPass), ActiveNetParams, nil) if err != nil { return err } if err := manager.Close(); err != nil { return err } if err := db.Close(); err != nil { return err } fmt.Println("The lnwallet has been created successfully.") return nil }
// TestCreateOpenUnsupported ensures that attempting to create or open an // unsupported database type is handled properly. func TestCreateOpenUnsupported(t *testing.T) { // Ensure creating a database with an unsupported type fails with the // expected error. dbType := "unsupported" _, err := walletdb.Create(dbType) if err != walletdb.ErrDbUnknownType { t.Errorf("expected error not received - got: %v, want %v", err, walletdb.ErrDbUnknownType) return } // Ensure opening a database with the an unsupported type fails with the // expected error. _, err = walletdb.Open(dbType) if err != walletdb.ErrDbUnknownType { t.Errorf("expected error not received - got: %v, want %v", err, walletdb.ErrDbUnknownType) return } }
// TestAddDuplicateDriver ensures that adding a duplicate driver does not // overwrite an existing one. func TestAddDuplicateDriver(t *testing.T) { supportedDrivers := walletdb.SupportedDrivers() if len(supportedDrivers) == 0 { t.Errorf("no backends to test") return } dbType := supportedDrivers[0] // bogusCreateDB is a function which acts as a bogus create and open // driver function and intentionally returns a failure that can be // detected if the interface allows a duplicate driver to overwrite an // existing one. bogusCreateDB := func(args ...interface{}) (walletdb.DB, error) { return nil, fmt.Errorf("duplicate driver allowed for database "+ "type [%v]", dbType) } // Create a driver that tries to replace an existing one. Set its // create and open functions to a function that causes a test failure if // they are invoked. driver := walletdb.Driver{ DbType: dbType, Create: bogusCreateDB, Open: bogusCreateDB, } err := walletdb.RegisterDriver(driver) if err != walletdb.ErrDbTypeRegistered { t.Errorf("unexpected duplicate driver registration error - "+ "got %v, want %v", err, walletdb.ErrDbTypeRegistered) } dbPath := "dupdrivertest.db" db, err := walletdb.Create(dbType, dbPath) if err != nil { t.Errorf("failed to create database: %v", err) return } db.Close() _ = os.Remove(dbPath) }
// TestCreateOpenFail ensures that errors which occur while opening or closing // a database are handled properly. func TestCreateOpenFail(t *testing.T) { // bogusCreateDB is a function which acts as a bogus create and open // driver function that intentionally returns a failure which can be // detected. dbType := "createopenfail" openError := fmt.Errorf("failed to create or open database for "+ "database type [%v]", dbType) bogusCreateDB := func(args ...interface{}) (walletdb.DB, error) { return nil, openError } // Create and add driver that intentionally fails when created or opened // to ensure errors on database open and create are handled properly. driver := walletdb.Driver{ DbType: dbType, Create: bogusCreateDB, Open: bogusCreateDB, } walletdb.RegisterDriver(driver) // Ensure creating a database with the new type fails with the expected // error. _, err := walletdb.Create(dbType) if err != openError { t.Errorf("expected error not received - got: %v, want %v", err, openError) return } // Ensure opening a database with the new type fails with the expected // error. _, err = walletdb.Open(dbType) if err != openError { t.Errorf("expected error not received - got: %v, want %v", err, openError) return } }
// This example demonstrates creating a new database. func ExampleCreate() { // This example assumes the bdb (bolt db) driver is imported. // // import ( // "github.com/btcsuite/btcwallet/walletdb" // _ "github.com/btcsuite/btcwallet/walletdb/bdb" // ) // Create a database and schedule it to be closed and removed on exit. // Typically you wouldn't want to remove the database right away like // this, but it's done here in the example to ensure the example cleans // up after itself. dbPath := filepath.Join(os.TempDir(), "examplecreate.db") db, err := walletdb.Create("bdb", dbPath) if err != nil { fmt.Println(err) return } defer os.Remove(dbPath) defer db.Close() // Output: }
// This example demonstrates creating a new database, getting a namespace from // it, and using a managed read-write transaction against the namespace to store // and retrieve data. func Example_basicUsage() { // This example assumes the bdb (bolt db) driver is imported. // // import ( // "github.com/btcsuite/btcwallet/walletdb" // _ "github.com/btcsuite/btcwallet/walletdb/bdb" // ) // Create a database and schedule it to be closed and removed on exit. // Typically you wouldn't want to remove the database right away like // this, but it's done here in the example to ensure the example cleans // up after itself. dbPath := filepath.Join(os.TempDir(), "exampleusage.db") db, err := walletdb.Create("bdb", dbPath) if err != nil { fmt.Println(err) return } defer os.Remove(dbPath) defer db.Close() // Get or create a namespace in the database as needed. This namespace // is what is typically passed to specific sub-packages so they have // their own area to work in without worrying about conflicting keys. namespaceKey := []byte("walletsubpackage") namespace, err := db.Namespace(namespaceKey) if err != nil { fmt.Println(err) return } // Use the Update function of the namespace to perform a managed // read-write transaction. The transaction will automatically be rolled // back if the supplied inner function returns a non-nil error. err = namespace.Update(func(tx walletdb.Tx) error { // All data is stored against the root bucket of the namespace, // or nested buckets of the root bucket. It's not really // necessary to store it in a separate variable like this, but // it has been done here for the purposes of the example to // illustrate. rootBucket := tx.RootBucket() // Store a key/value pair directly in the root bucket. key := []byte("mykey") value := []byte("myvalue") if err := rootBucket.Put(key, value); err != nil { return err } // Read the key back and ensure it matches. if !bytes.Equal(rootBucket.Get(key), value) { return fmt.Errorf("unexpected value for key '%s'", key) } // Create a new nested bucket under the root bucket. nestedBucketKey := []byte("mybucket") nestedBucket, err := rootBucket.CreateBucket(nestedBucketKey) if err != nil { return err } // The key from above that was set in the root bucket does not // exist in this new nested bucket. if nestedBucket.Get(key) != nil { return fmt.Errorf("key '%s' is not expected nil", key) } return nil }) if err != nil { fmt.Println(err) return } // Output: }
// TestPersistence ensures that values stored are still valid after closing and // reopening the database. func TestPersistence(t *testing.T) { // Create a new database to run tests against. dbPath := "persistencetest.db" db, err := walletdb.Create(dbType, dbPath) if err != nil { t.Errorf("Failed to create test database (%s) %v", dbType, err) return } defer os.Remove(dbPath) defer db.Close() // Create a namespace and put some values into it so they can be tested // for existence on re-open. storeValues := map[string]string{ "ns1key1": "foo1", "ns1key2": "foo2", "ns1key3": "foo3", } ns1Key := []byte("ns1") ns1, err := db.Namespace(ns1Key) if err != nil { t.Errorf("Namespace: unexpected error: %v", err) return } err = ns1.Update(func(tx walletdb.Tx) error { rootBucket := tx.RootBucket() if rootBucket == nil { return fmt.Errorf("RootBucket: unexpected nil root bucket") } for k, v := range storeValues { if err := rootBucket.Put([]byte(k), []byte(v)); err != nil { return fmt.Errorf("Put: unexpected error: %v", err) } } return nil }) if err != nil { t.Errorf("ns1 Update: unexpected error: %v", err) return } // Close and reopen the database to ensure the values persist. db.Close() db, err = walletdb.Open(dbType, dbPath) if err != nil { t.Errorf("Failed to open test database (%s) %v", dbType, err) return } defer db.Close() // Ensure the values previously stored in the 3rd namespace still exist // and are correct. ns1, err = db.Namespace(ns1Key) if err != nil { t.Errorf("Namespace: unexpected error: %v", err) return } err = ns1.View(func(tx walletdb.Tx) error { rootBucket := tx.RootBucket() if rootBucket == nil { return fmt.Errorf("RootBucket: unexpected nil root bucket") } for k, v := range storeValues { gotVal := rootBucket.Get([]byte(k)) if !reflect.DeepEqual(gotVal, []byte(v)) { return fmt.Errorf("Get: key '%s' does not "+ "match expected value - got %s, want %s", k, gotVal, v) } } return nil }) if err != nil { t.Errorf("ns1 View: unexpected error: %v", err) return } }
// TestCreateOpenFail ensures that errors related to creating and opening a // database are handled properly. func TestCreateOpenFail(t *testing.T) { // Ensure that attempting to open a database that doesn't exist returns // the expected error. wantErr := walletdb.ErrDbDoesNotExist if _, err := walletdb.Open(dbType, "noexist.db"); err != wantErr { t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) return } // Ensure that attempting to open a database with the wrong number of // parameters returns the expected error. wantErr = fmt.Errorf("invalid arguments to %s.Open -- expected "+ "database path", dbType) if _, err := walletdb.Open(dbType, 1, 2, 3); err.Error() != wantErr.Error() { t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) return } // Ensure that attempting to open a database with an invalid type for // the first parameter returns the expected error. wantErr = fmt.Errorf("first argument to %s.Open is invalid -- "+ "expected database path string", dbType) if _, err := walletdb.Open(dbType, 1); err.Error() != wantErr.Error() { t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) return } // Ensure that attempting to create a database with the wrong number of // parameters returns the expected error. wantErr = fmt.Errorf("invalid arguments to %s.Create -- expected "+ "database path", dbType) if _, err := walletdb.Create(dbType, 1, 2, 3); err.Error() != wantErr.Error() { t.Errorf("Create: did not receive expected error - got %v, "+ "want %v", err, wantErr) return } // Ensure that attempting to open a database with an invalid type for // the first parameter returns the expected error. wantErr = fmt.Errorf("first argument to %s.Create is invalid -- "+ "expected database path string", dbType) if _, err := walletdb.Create(dbType, 1); err.Error() != wantErr.Error() { t.Errorf("Create: did not receive expected error - got %v, "+ "want %v", err, wantErr) return } // Ensure operations against a closed database return the expected // error. dbPath := "createfail.db" db, err := walletdb.Create(dbType, dbPath) if err != nil { t.Errorf("Create: unexpected error: %v", err) return } defer os.Remove(dbPath) db.Close() wantErr = walletdb.ErrDbNotOpen if _, err := db.Namespace([]byte("ns1")); err != wantErr { t.Errorf("Namespace: did not receive expected error - got %v, "+ "want %v", err, wantErr) return } }
// CreateNewWallet creates a new wallet using the provided public and private // passphrases. The seed is optional. If non-nil, addresses are derived from // this seed. If nil, a secure random seed is generated. func (l *Loader) CreateNewWallet(pubPassphrase, privPassphrase, seed []byte) (*Wallet, error) { defer l.mu.Unlock() l.mu.Lock() if l.wallet != nil { return nil, ErrLoaded } dbPath := filepath.Join(l.dbDirPath, walletDbName) exists, err := fileExists(dbPath) if err != nil { return nil, err } if exists { return nil, ErrExists } // Create the wallet database backed by bolt db. err = os.MkdirAll(l.dbDirPath, 0700) if err != nil { return nil, err } db, err := walletdb.Create("bdb", dbPath) if err != nil { return nil, err } // Create the address manager. if seed != nil { if len(seed) < hdkeychain.MinSeedBytes || len(seed) > hdkeychain.MaxSeedBytes { return nil, hdkeychain.ErrInvalidSeedLen } } addrMgrNamespace, err := db.Namespace(waddrmgrNamespaceKey) if err != nil { return nil, err } _, err = waddrmgr.Create(addrMgrNamespace, seed, pubPassphrase, privPassphrase, l.chainParams, nil) if err != nil { return nil, err } // Create empty transaction manager. txMgrNamespace, err := db.Namespace(wtxmgrNamespaceKey) if err != nil { return nil, err } _, err = wtxmgr.Create(txMgrNamespace) if err != nil { return nil, err } // Open the newly-created wallet. w, err := Open(pubPassphrase, l.chainParams, db, addrMgrNamespace, txMgrNamespace, nil) if err != nil { return nil, err } l.onLoaded(w, db) return w, nil }
// createWallet prompts the user for information needed to generate a new wallet // and generates the wallet accordingly. The new wallet will reside at the // provided path. func createWallet(cfg *config) error { // When there is a legacy keystore, open it now to ensure any errors // don't end up exiting the process after the user has spent time // entering a bunch of information. netDir := networkDir(cfg.DataDir, activeNet.Params) keystorePath := filepath.Join(netDir, keystore.Filename) var legacyKeyStore *keystore.Store if fileExists(keystorePath) { var err error legacyKeyStore, err = keystore.OpenDir(netDir) if err != nil { return err } } // Start by prompting for the private passphrase. When there is an // existing keystore, the user will be promped for that passphrase, // otherwise they will be prompted for a new one. reader := bufio.NewReader(os.Stdin) privPass, err := promptConsolePrivatePass(reader, legacyKeyStore) if err != nil { return err } // Ascertain the public passphrase. This will either be a value // specified by the user or the default hard-coded public passphrase if // the user does not want the additional public data encryption. pubPass, err := promptConsolePublicPass(reader, privPass, cfg) if err != nil { return err } // Ascertain the wallet generation seed. This will either be an // automatically generated value the user has already confirmed or a // value the user has entered which has already been validated. seed, err := promptConsoleSeed(reader) if err != nil { return err } // Create the wallet. dbPath := filepath.Join(netDir, walletDbName) fmt.Println("Creating the wallet...") // Create the wallet database backed by bolt db. db, err := walletdb.Create("bdb", dbPath) if err != nil { return err } // Create the address manager. namespace, err := db.Namespace(waddrmgrNamespaceKey) if err != nil { return err } manager, err := waddrmgr.Create(namespace, seed, []byte(pubPass), []byte(privPass), activeNet.Params, nil) if err != nil { return err } // Import the addresses in the legacy keystore to the new wallet if // any exist. if legacyKeyStore != nil { fmt.Println("Importing addresses from existing wallet...") if err := manager.Unlock([]byte(privPass)); err != nil { return err } if err := convertLegacyKeystore(legacyKeyStore, manager); err != nil { return err } legacyKeyStore.Lock() legacyKeyStore = nil // Remove the legacy key store. if err := os.Remove(keystorePath); err != nil { fmt.Printf("WARN: Failed to remove legacy wallet "+ "from'%s'\n", keystorePath) } } manager.Close() fmt.Println("The wallet has been created successfully.") return nil }