OSDN Git Service

remove key import export
authorYongfeng LI <wliyongfeng@gmail.com>
Tue, 17 Apr 2018 11:38:00 +0000 (19:38 +0800)
committerYongfeng LI <wliyongfeng@gmail.com>
Tue, 17 Apr 2018 11:38:00 +0000 (19:38 +0800)
api/api.go
api/wallet.go
cmd/bytomcli/commands/bytomcli.go
cmd/bytomcli/commands/key.go
node/node.go
wallet/indexer.go
wallet/set.go [deleted file]
wallet/wallet.go
wallet/wallet_test.go

index 6eb382d..d1e0610 100644 (file)
@@ -184,10 +184,6 @@ func (a *API) buildHandler() {
                m.Handle("/delete-key", jsonHandler(a.pseudohsmDeleteKey))
                m.Handle("/reset-key-password", jsonHandler(a.pseudohsmResetPassword))
 
-               m.Handle("/export-private-key", jsonHandler(a.walletExportKey))
-               m.Handle("/import-private-key", jsonHandler(a.walletImportKey))
-               m.Handle("/import-key-progress", jsonHandler(a.keyImportProgress))
-
                m.Handle("/build-transaction", jsonHandler(a.build))
                m.Handle("/sign-transaction", jsonHandler(a.pseudohsmSignTemplates))
                m.Handle("/submit-transaction", jsonHandler(a.submit))
index ec950c0..ac593ae 100644 (file)
@@ -1,74 +1,9 @@
 package api
 
 import (
-       "bytes"
-       "context"
-
-       "github.com/tendermint/go-wire/data/base58"
-
-       "github.com/bytom/crypto/ed25519/chainkd"
-       "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/errors"
 )
 
-//KeyImportParams private key import param
-type KeyImportParams struct {
-       KeyAlias     string `json:"alias"`
-       Password     string `json:"password"`
-       XPrv         string `json:"xprv"`
-       Index        uint64 `json:"index"`
-       AccountAlias string `json:"account_alias"`
-}
-
-func (a *API) walletExportKey(ctx context.Context, in struct {
-       Password string       `json:"password"`
-       XPub     chainkd.XPub `json:"xpub"`
-}) Response {
-       key, err := a.wallet.ExportAccountPrivKey(in.XPub, in.Password)
-       if err != nil {
-               return NewErrorResponse(err)
-       }
-
-       type privateKey struct {
-               PrivateKey string `json:"private_key"`
-       }
-       return NewSuccessResponse(privateKey{PrivateKey: *key})
-}
-
-func (a *API) walletImportKey(ctx context.Context, in KeyImportParams) Response {
-       rawData, err := base58.Decode(in.XPrv)
-       if err != nil {
-               return NewErrorResponse(err)
-       }
-
-       if len(rawData) != 68 {
-               return NewErrorResponse(errors.New("invalid private key hash length"))
-       }
-
-       var hashed [32]byte
-       sha3pool.Sum256(hashed[:], rawData[:64])
-       if res := bytes.Compare(hashed[:4], rawData[64:]); res != 0 {
-               return NewErrorResponse(errors.New("private hash error"))
-       }
-
-       var xprv [64]byte
-       copy(xprv[:], rawData[:64])
-
-       xpub, err := a.wallet.ImportAccountPrivKey(xprv, in.KeyAlias, in.Password, in.Index, in.AccountAlias)
-       if err != nil {
-               return NewErrorResponse(err)
-       }
-       return NewSuccessResponse(xpub)
-}
-
-func (a *API) keyImportProgress(ctx context.Context) Response {
-       data, err := a.wallet.GetRescanStatus()
-       if err != nil {
-               return NewErrorResponse(err)
-       }
-       return NewSuccessResponse(data)
-}
-
 // POST /wallet error
 func (a *API) walletError() Response {
        return NewErrorResponse(errors.New("wallet not found, please check that the wallet is open"))
index 1c1ca6c..d11c6fd 100644 (file)
@@ -115,9 +115,6 @@ func AddCommands() {
        BytomcliCmd.AddCommand(deleteKeyCmd)
        BytomcliCmd.AddCommand(listKeysCmd)
        BytomcliCmd.AddCommand(resetKeyPwdCmd)
-       BytomcliCmd.AddCommand(exportPrivateCmd)
-       BytomcliCmd.AddCommand(importPrivateCmd)
-       BytomcliCmd.AddCommand(importKeyProgressCmd)
 
        BytomcliCmd.AddCommand(isMiningCmd)
 
index 61f0dcc..a1cd64e 100644 (file)
@@ -1,15 +1,10 @@
 package commands
 
 import (
-       "encoding/hex"
-       "fmt"
        "os"
-       "strconv"
-
        "github.com/spf13/cobra"
        jww "github.com/spf13/jwalterweatherman"
 
-       "github.com/bytom/api"
        "github.com/bytom/crypto/ed25519/chainkd"
        "github.com/bytom/util"
 )
@@ -93,69 +88,3 @@ var resetKeyPwdCmd = &cobra.Command{
                jww.FEEDBACK.Println("Successfully reset key password")
        },
 }
-
-var exportPrivateCmd = &cobra.Command{
-       Use:   "export-private-key <xpub> <password>",
-       Short: "Export the private key",
-       Args:  cobra.ExactArgs(2),
-       Run: func(cmd *cobra.Command, args []string) {
-               type Key struct {
-                       Password string
-                       XPub     chainkd.XPub
-               }
-               var key Key
-               xpub := new(chainkd.XPub)
-               rawPub, err := hex.DecodeString(args[0])
-               if err != nil {
-                       jww.ERROR.Println("error: export-private-key args not vaild", err)
-               }
-               copy(xpub[:], rawPub)
-
-               key.XPub = *xpub
-               key.Password = args[1]
-
-               data, exitCode := util.ClientCall("/export-private-key", &key)
-               if exitCode != util.Success {
-                       os.Exit(exitCode)
-               }
-
-               printJSON(data)
-       },
-}
-
-var importPrivateCmd = &cobra.Command{
-       Use:   "import-private-key <key-alias> <private key> <index> <password> <account-alias>",
-       Short: "Import the private key",
-       Args:  cobra.ExactArgs(5),
-       Run: func(cmd *cobra.Command, args []string) {
-               var params api.KeyImportParams
-               params.KeyAlias = args[0]
-               params.XPrv = args[1]
-               params.Password = args[3]
-               params.AccountAlias = args[4]
-               index, err := strconv.ParseUint(args[2], 10, 64)
-               if err != nil {
-                       jww.ERROR.Println("params index wrong")
-               }
-               params.Index = index
-
-               data, exitCode := util.ClientCall("/import-private-key", &params)
-               if exitCode != util.Success {
-                       os.Exit(exitCode)
-               }
-               printJSON(data)
-       },
-}
-
-var importKeyProgressCmd = &cobra.Command{
-       Use:   "import-key-progress",
-       Short: "Get import private key progress info",
-       Args:  cobra.NoArgs,
-       Run: func(cmd *cobra.Command, args []string) {
-               data, exitCode := util.ClientCall("/import-key-progress")
-               if exitCode != util.Success {
-                       os.Exit(exitCode)
-               }
-               fmt.Println("data:", data)
-       },
-}
index 46909cf..3ccee7b 100644 (file)
@@ -162,20 +162,10 @@ func initOrRecoverAccount(hsm *pseudohsm.HSM, wallet *w.Wallet) error {
                return nil
        }
 
-       accounts, err := wallet.AccountMgr.ListAccounts("")
-       if err != nil {
+       if _, err := wallet.AccountMgr.ListAccounts(""); err != nil {
                return err
        }
 
-       if len(accounts) > 0 {
-               return nil
-       }
-
-       for i, xPub := range xpubs {
-               if err := wallet.ImportAccountXpubKey(i, xPub, w.RecoveryIndex); err != nil {
-                       return err
-               }
-       }
        return nil
 }
 
@@ -237,5 +227,3 @@ func (n *Node) SyncManager() *netsync.SyncManager {
 func (n *Node) MiningPool() *miningpool.MiningPool {
        return n.miningPool
 }
-
-//------------------------------------------------------------------------------
index 436faff..2d5fd79 100644 (file)
@@ -383,25 +383,15 @@ func (w *Wallet) filterAccountTxs(b *types.Block, txStatus *bc.TransactionStatus
 transactionLoop:
        for pos, tx := range b.Transactions {
                statusFail, _ := txStatus.GetStatus(pos)
-               isLocal := false
                for _, v := range tx.Outputs {
                        var hash [32]byte
                        sha3pool.Sum256(hash[:], v.ControlProgram)
                        if bytes := w.DB.Get(account.CPKey(hash)); bytes != nil {
-                               cp := &account.CtrlProgram{}
-                               if err := json.Unmarshal(bytes, cp); err == nil {
-                                       w.status.OnChainAddresses.Add(cp.Address)
-                               }
-
                                annotatedTxs = append(annotatedTxs, w.buildAnnotatedTransaction(tx, b, statusFail, pos))
-                               isLocal = true
+                               continue transactionLoop
                        }
                }
 
-               if isLocal {
-                       continue
-               }
-
                for _, v := range tx.Inputs {
                        outid, err := v.SpentOutputID()
                        if err != nil {
diff --git a/wallet/set.go b/wallet/set.go
deleted file mode 100644 (file)
index 5a8c785..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-package wallet
-
-type AddressSet map[string]bool
-
-func NewAddressSet() AddressSet {
-       return make(AddressSet)
-}
-
-// Add Add the specified element to this set if it is not already present (optional operation)
-func (s *AddressSet) Add(i string) bool {
-       _, found := (*s)[i]
-       if found {
-               return false //False if it existed already
-       }
-
-       (*s)[i] = true
-       return true
-}
-
-// Contains Returns true if this set contains the specified elements
-func (s *AddressSet) Contains(i ...string) bool {
-       for _, val := range i {
-               if _, ok := (*s)[val]; !ok {
-                       return false
-               }
-       }
-       return true
-}
index 55ea6e7..a5143c3 100644 (file)
@@ -2,17 +2,12 @@ package wallet
 
 import (
        "encoding/json"
-       "fmt"
-
        log "github.com/sirupsen/logrus"
-       "github.com/tendermint/go-wire/data/base58"
        "github.com/tendermint/tmlibs/db"
 
        "github.com/bytom/account"
        "github.com/bytom/asset"
        "github.com/bytom/blockchain/pseudohsm"
-       "github.com/bytom/crypto/ed25519/chainkd"
-       "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/protocol"
        "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/types"
@@ -25,7 +20,6 @@ const SINGLE = 1
 const RecoveryIndex = 5000
 
 var walletKey = []byte("walletInfo")
-var dbKeyForimportingPrivateKey = []byte("importingKeysInfo")
 
 //StatusInfo is base valid block info to handle orphan block rollback
 type StatusInfo struct {
@@ -33,16 +27,6 @@ type StatusInfo struct {
        WorkHash         bc.Hash
        BestHeight       uint64
        BestHash         bc.Hash
-       OnChainAddresses AddressSet
-}
-
-//KeyInfo is key import status
-type KeyInfo struct {
-       account  account.Account
-       Alias    string       `json:"alias"`
-       XPub     chainkd.XPub `json:"xpub"`
-       Percent  uint8        `json:"percent"`
-       Complete bool         `json:"complete"`
 }
 
 //Wallet is related to storing account unspent outputs
@@ -53,9 +37,6 @@ type Wallet struct {
        AssetReg            *asset.Registry
        Hsm                 *pseudohsm.HSM
        chain               *protocol.Chain
-       rescanProgress      chan struct{}
-       ImportingPrivateKey bool
-       importingKeysInfo   []KeyInfo
 }
 
 //NewWallet return a new wallet instance
@@ -66,20 +47,12 @@ func NewWallet(walletDB db.DB, account *account.Manager, asset *asset.Registry,
                AssetReg:            asset,
                chain:               chain,
                Hsm:                 hsm,
-               rescanProgress:      make(chan struct{}, 1),
-               importingKeysInfo:   make([]KeyInfo, 0),
        }
 
        if err := w.loadWalletInfo(); err != nil {
                return nil, err
        }
 
-       if err := w.loadKeysInfo(); err != nil {
-               return nil, err
-       }
-
-       w.ImportingPrivateKey = w.getImportKeyFlag()
-
        go w.walletUpdater()
 
        return w, nil
@@ -92,7 +65,6 @@ func (w *Wallet) loadWalletInfo() error {
                return json.Unmarshal(rawWallet, &w.status)
        }
 
-       w.status.OnChainAddresses = NewAddressSet()
        block, err := w.chain.GetBlockByHeight(0)
        if err != nil {
                return err
@@ -112,35 +84,6 @@ func (w *Wallet) commitWalletInfo(batch db.Batch) error {
        return nil
 }
 
-//GetWalletInfo return stored wallet info and nil,if error,
-//return initial wallet info and err
-func (w *Wallet) loadKeysInfo() error {
-       if rawKeyInfo := w.DB.Get(dbKeyForimportingPrivateKey); rawKeyInfo != nil {
-               json.Unmarshal(rawKeyInfo, &w.importingKeysInfo)
-               return nil
-       }
-       return nil
-}
-
-func (w *Wallet) commitkeysInfo() error {
-       rawKeysInfo, err := json.Marshal(w.importingKeysInfo)
-       if err != nil {
-               log.WithField("err", err).Error("save wallet info")
-               return err
-       }
-       w.DB.Set(dbKeyForimportingPrivateKey, rawKeysInfo)
-       return nil
-}
-
-func (w *Wallet) getImportKeyFlag() bool {
-       for _, v := range w.importingKeysInfo {
-               if v.Complete == false {
-                       return true
-               }
-       }
-       return false
-}
-
 // AttachBlock attach a new block
 func (w *Wallet) AttachBlock(block *types.Block) error {
        if block.PreviousBlockHash != w.status.WorkHash {
@@ -193,8 +136,6 @@ func (w *Wallet) DetachBlock(block *types.Block) error {
 //WalletUpdate process every valid block and reverse every invalid block which need to rollback
 func (w *Wallet) walletUpdater() {
        for {
-               getRescanNotification(w)
-               w.updateRescanStatus()
                for !w.chain.InMainChain(w.status.BestHash) {
                        block, err := w.chain.GetBlockByHash(&w.status.BestHash)
                        if err != nil {
@@ -221,96 +162,6 @@ func (w *Wallet) walletUpdater() {
        }
 }
 
-func getRescanNotification(w *Wallet) {
-       select {
-       case <-w.rescanProgress:
-               w.status.WorkHeight = 0
-               block, _ := w.chain.GetBlockByHeight(w.status.WorkHeight)
-               w.status.WorkHash = block.Hash()
-       default:
-               return
-       }
-}
-
-// ExportAccountPrivKey exports the account private key as a WIF for encoding as a string
-// in the Wallet Import Formt.
-func (w *Wallet) ExportAccountPrivKey(xpub chainkd.XPub, auth string) (*string, error) {
-       xprv, err := w.Hsm.LoadChainKDKey(xpub, auth)
-       if err != nil {
-               return nil, err
-       }
-       var hashed [32]byte
-       sha3pool.Sum256(hashed[:], xprv[:])
-
-       tmp := append(xprv[:], hashed[:4]...)
-       res := base58.Encode(tmp)
-       return &res, nil
-}
-
-// ImportAccountPrivKey imports the account key in the Wallet Import Formt.
-func (w *Wallet) ImportAccountPrivKey(xprv chainkd.XPrv, keyAlias, auth string, index uint64, accountAlias string) (*pseudohsm.XPub, error) {
-       if w.Hsm.HasAlias(keyAlias) {
-               return nil, pseudohsm.ErrDuplicateKeyAlias
-       }
-       if w.Hsm.HasKey(xprv) {
-               return nil, pseudohsm.ErrDuplicateKey
-       }
-
-       if acc, _ := w.AccountMgr.FindByAlias(nil, accountAlias); acc != nil {
-               return nil, account.ErrDuplicateAlias
-       }
-
-       xpub, _, err := w.Hsm.ImportXPrvKey(auth, keyAlias, xprv)
-       if err != nil {
-               return nil, err
-       }
-
-       newAccount, err := w.AccountMgr.Create(nil, []chainkd.XPub{xpub.XPub}, SINGLE, accountAlias)
-       if err != nil {
-               w.Hsm.XDelete(xpub.XPub, auth)
-               return nil, err
-       }
-       if err := w.recoveryAccountWalletDB(newAccount, xpub, index, keyAlias); err != nil {
-               w.AccountMgr.DeleteAccount(newAccount.ID)
-               w.Hsm.XDelete(xpub.XPub, auth)
-               return nil, err
-       }
-       return xpub, nil
-}
-
-// ImportAccountXpubKey imports the account key in the Wallet Import Formt.
-func (w *Wallet) ImportAccountXpubKey(xpubIndex int, xpub pseudohsm.XPub, cpIndex uint64) error {
-       accountAlias := fmt.Sprintf("recovery_%d", xpubIndex)
-
-       if acc, _ := w.AccountMgr.FindByAlias(nil, accountAlias); acc != nil {
-               return account.ErrDuplicateAlias
-       }
-
-       newAccount, err := w.AccountMgr.Create(nil, []chainkd.XPub{xpub.XPub}, SINGLE, accountAlias)
-       if err != nil {
-               return err
-       }
-
-       return w.recoveryAccountWalletDB(newAccount, &xpub, cpIndex, xpub.Alias)
-}
-
-func (w *Wallet) recoveryAccountWalletDB(account *account.Account, XPub *pseudohsm.XPub, index uint64, keyAlias string) error {
-       if err := w.createProgram(account, XPub, index); err != nil {
-               return err
-       }
-       w.ImportingPrivateKey = true
-       tmp := KeyInfo{
-               account:  *account,
-               Alias:    keyAlias,
-               XPub:     XPub.XPub,
-               Complete: false,
-       }
-       w.importingKeysInfo = append(w.importingKeysInfo, tmp)
-       w.commitkeysInfo()
-       w.rescanBlocks()
-
-       return nil
-}
 
 func (w *Wallet) createProgram(account *account.Account, XPub *pseudohsm.XPub, index uint64) error {
        for i := uint64(0); i < index; i++ {
@@ -320,55 +171,3 @@ func (w *Wallet) createProgram(account *account.Account, XPub *pseudohsm.XPub, i
        }
        return nil
 }
-
-func (w *Wallet) rescanBlocks() {
-       select {
-       case w.rescanProgress <- struct{}{}:
-       default:
-               return
-       }
-}
-
-//GetRescanStatus return key import rescan status
-func (w *Wallet) GetRescanStatus() ([]KeyInfo, error) {
-       keysInfo := make([]KeyInfo, len(w.importingKeysInfo))
-
-       if rawKeyInfo := w.DB.Get(dbKeyForimportingPrivateKey); rawKeyInfo != nil {
-               if err := json.Unmarshal(rawKeyInfo, &keysInfo); err != nil {
-                       return nil, err
-               }
-       }
-
-       return keysInfo, nil
-}
-
-//updateRescanStatus mark private key import process `Complete` if rescan finished
-func (w *Wallet) updateRescanStatus() {
-       if !w.ImportingPrivateKey {
-               return
-       }
-
-       if w.status.WorkHeight < w.status.BestHeight {
-               percent := uint8(w.status.WorkHeight * 100 / w.status.BestHeight)
-               for _, keyInfo := range w.importingKeysInfo {
-                       keyInfo.Percent = percent
-               }
-               w.commitkeysInfo()
-               return
-       }
-
-       w.ImportingPrivateKey = false
-       for _, keyInfo := range w.importingKeysInfo {
-               keyInfo.Percent = 100
-               keyInfo.Complete = true
-
-               if cps, err := w.AccountMgr.ListCtrlProgramsByAccountId(nil, keyInfo.account.ID); err == nil {
-                       for _, cp := range cps {
-                               if !w.status.OnChainAddresses.Contains(cp.Address) {
-                                       w.AccountMgr.DeleteAccountControlProgram(cp.ControlProgram)
-                               }
-                       }
-               }
-       }
-       w.commitkeysInfo()
-}
index 4ba4ce7..1da96f3 100644 (file)
@@ -1,13 +1,11 @@
 package wallet
 
 import (
-       "context"
        "io/ioutil"
        "os"
        "testing"
        "time"
 
-       "github.com/tendermint/go-wire/data/base58"
        dbm "github.com/tendermint/tmlibs/db"
 
        "github.com/bytom/account"
@@ -16,7 +14,6 @@ import (
        "github.com/bytom/blockchain/txbuilder"
        "github.com/bytom/consensus"
        "github.com/bytom/crypto/ed25519/chainkd"
-       "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/database/leveldb"
        "github.com/bytom/protocol"
        "github.com/bytom/protocol/bc"
@@ -103,101 +100,6 @@ func TestWalletUpdate(t *testing.T) {
        }
 }
 
-func TestExportAndImportPrivKey(t *testing.T) {
-       dirPath, err := ioutil.TempDir(".", "")
-       if err != nil {
-               t.Fatal(err)
-       }
-       defer os.RemoveAll(dirPath)
-
-       testDB := dbm.NewDB("testdb", "leveldb", "temp")
-       defer os.RemoveAll("temp")
-
-       store := leveldb.NewStore(testDB)
-       txPool := protocol.NewTxPool()
-
-       chain, err := protocol.NewChain(store, txPool)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       acntManager := account.NewManager(testDB, chain)
-       reg := asset.NewRegistry(testDB, chain)
-
-       hsm, err := pseudohsm.New(dirPath)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       pwd := "password"
-       xpub, err := hsm.XCreate("alias", pwd)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       w, err := NewWallet(testDB, acntManager, reg, hsm, chain)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       ctx := context.Background()
-       acnt1, err := w.AccountMgr.Create(ctx, []chainkd.XPub{xpub.XPub}, 1, "account-alias")
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       priv, err := w.ExportAccountPrivKey(xpub.XPub, pwd)
-
-       wantPriv, err := hsm.LoadChainKDKey(xpub.XPub, pwd)
-       if err != nil {
-               t.Fatal(err)
-       }
-       var hashed [32]byte
-       sha3pool.Sum256(hashed[:], wantPriv[:])
-
-       tmp := append(wantPriv[:], hashed[:4]...)
-       res := base58.Encode(tmp)
-
-       if res != *priv {
-               t.Fatalf("XPrivs should be identical.\nBefore: %v\n After: %v\n", *priv, res)
-       }
-
-       rawPriv, err := base58.Decode(*priv)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       if len(rawPriv) != 68 {
-               t.Fatal("invalid private key hash length")
-       }
-
-       var xprv [64]byte
-       copy(xprv[:], rawPriv[:64])
-
-       _, err = w.ImportAccountPrivKey(xprv, xpub.Alias, pwd, 0, acnt1.Alias)
-       if err != pseudohsm.ErrDuplicateKeyAlias {
-               t.Fatal(err)
-       }
-
-       hsm.XDelete(xpub.XPub, pwd)
-
-       _, err = w.ImportAccountPrivKey(xprv, xpub.Alias, pwd, 0, acnt1.Alias)
-       if err != account.ErrDuplicateAlias {
-               t.Fatal(err)
-       }
-
-       w.AccountMgr.DeleteAccount(acnt1.Alias)
-
-       acnt2, err := w.ImportAccountPrivKey(xprv, xpub.Alias, pwd, 0, acnt1.Alias)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       if acnt2.XPub != acnt1.XPubs[0] {
-               t.Fatalf("XPubs should be identical.\nBefore: %v\n After: %v\n", acnt1.XPubs[0], acnt2.XPub)
-       }
-}
-
 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
        utxo := &account.UTXO{}
        utxo.OutputID = bc.Hash{V0: 1}
@@ -240,10 +142,6 @@ func mockWallet(walletDB dbm.DB, account *account.Manager, asset *asset.Registry
                AccountMgr:          account,
                AssetReg:            asset,
                chain:               chain,
-               rescanProgress:      make(chan struct{}, 1),
-       }
-       wallet.status = StatusInfo{
-               OnChainAddresses: NewAddressSet(),
        }
        return wallet
 }