neat: accounts and wallet api sorted out
Unused endpoints removed, new ones with more meaningful naming are added and their purposes were revised.
This commit is contained in:
parent
a812365525
commit
d30c88b80e
|
@ -3,7 +3,6 @@ package accounts
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -15,14 +14,10 @@ import (
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
"github.com/status-im/status-go/multiaccounts/keypairs"
|
"github.com/status-im/status-go/multiaccounts/keypairs"
|
||||||
"github.com/status-im/status-go/multiaccounts/settings"
|
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/protocol"
|
"github.com/status-im/status-go/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
const pathWalletRoot = "m/44'/60'/0'/0"
|
|
||||||
const pathDefaultWallet = pathWalletRoot + "/0"
|
|
||||||
|
|
||||||
func NewAccountsAPI(manager *account.GethManager, config *params.NodeConfig, db *accounts.Database, feed *event.Feed, messenger **protocol.Messenger) *API {
|
func NewAccountsAPI(manager *account.GethManager, config *params.NodeConfig, db *accounts.Database, feed *event.Feed, messenger **protocol.Messenger) *API {
|
||||||
return &API{manager, config, db, feed, messenger}
|
return &API{manager, config, db, feed, messenger}
|
||||||
}
|
}
|
||||||
|
@ -105,232 +100,100 @@ func (api *API) DeleteAccount(ctx context.Context, address types.Address, passwo
|
||||||
return (*api.messenger).DeleteAccount(address)
|
return (*api.messenger).DeleteAccount(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) AddAccountWatch(ctx context.Context, address string, name string, color string, emoji string) error {
|
func (api *API) AddAccount(ctx context.Context, password string, account *accounts.Account) error {
|
||||||
account := &accounts.Account{
|
if len(account.Address) == 0 {
|
||||||
Address: types.Address(common.HexToAddress(address)),
|
return errors.New("`Address` field must be set")
|
||||||
Type: accounts.AccountTypeWatch,
|
|
||||||
Name: name,
|
|
||||||
Emoji: emoji,
|
|
||||||
Color: color,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if account.Wallet || account.Chat {
|
||||||
|
return errors.New("default wallet and chat account cannot be added this way")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.Name) == 0 {
|
||||||
|
return errors.New("`Name` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.Emoji) == 0 {
|
||||||
|
return errors.New("`Emoji` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.Color) == 0 {
|
||||||
|
return errors.New("`Color` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if account.Type != accounts.AccountTypeWatch {
|
||||||
|
|
||||||
|
if len(account.KeyUID) == 0 {
|
||||||
|
return errors.New("`KeyUID` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.PublicKey) == 0 {
|
||||||
|
return errors.New("`PublicKey` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.KeypairName) == 0 {
|
||||||
|
return errors.New("`KeypairName` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if account.Type != accounts.AccountTypeKey {
|
||||||
|
if len(account.DerivedFrom) == 0 {
|
||||||
|
return errors.New("`DerivedFrom` field must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(account.Path) == 0 {
|
||||||
|
return errors.New("`Path` field must be set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addressExists, err := api.db.AddressExists(account.Address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if addressExists {
|
||||||
|
return errors.New("account already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to create local keystore file only if password is provided and the account is being added is of
|
||||||
|
// "generated" or "seed" type.
|
||||||
|
if (account.Type == accounts.AccountTypeGenerated || account.Type == accounts.AccountTypeSeed) && len(password) > 0 {
|
||||||
|
info, err := api.manager.AccountsGenerator().LoadAccount(account.DerivedFrom, password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = api.manager.AccountsGenerator().StoreDerivedAccounts(info.ID, password, []string{account.Path})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return api.SaveAccounts(ctx, []*accounts.Account{account})
|
return api.SaveAccounts(ctx, []*accounts.Account{account})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) AddAccountWithMnemonic(
|
// Imports a new private key and creates local keystore file.
|
||||||
ctx context.Context,
|
func (api *API) ImportPrivateKey(ctx context.Context, privateKey string, password string) error {
|
||||||
mnemonic string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
) error {
|
|
||||||
return api.addAccountWithMnemonic(ctx, mnemonic, password, name, color, emoji, pathWalletRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) AddAccountWithMnemonicPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
mnemonic string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
) error {
|
|
||||||
return api.addAccountWithMnemonicPasswordVerified(ctx, mnemonic, password, name, color, emoji, pathWalletRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) AddAccountWithMnemonicAndPath(
|
|
||||||
ctx context.Context,
|
|
||||||
mnemonic string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
) error {
|
|
||||||
return api.addAccountWithMnemonic(ctx, mnemonic, password, name, color, emoji, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) AddAccountWithMnemonicAndPathPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
mnemonic string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
) error {
|
|
||||||
return api.addAccountWithMnemonicPasswordVerified(ctx, mnemonic, password, name, color, emoji, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddAccountWithPrivateKeyPasswordVerified adds an accounts.Account created from the given private key
|
|
||||||
// assuming that client has already authenticated logged in use, this function doesn't verify a password.
|
|
||||||
func (api *API) AddAccountWithPrivateKeyPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
privateKey string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
) error {
|
|
||||||
|
|
||||||
info, err := api.manager.AccountsGenerator().ImportPrivateKey(privateKey)
|
info, err := api.manager.AccountsGenerator().ImportPrivateKey(privateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
addressExists, err := api.db.AddressExists(types.Address(common.HexToAddress(info.Address)))
|
accs, err := api.db.GetAccountsByKeyUID(info.KeyUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if addressExists {
|
|
||||||
return errors.New("account already exists")
|
if len(accs) > 0 {
|
||||||
|
return errors.New("provided private key was already imported")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = api.manager.AccountsGenerator().StoreAccount(info.ID, password)
|
_, err = api.manager.AccountsGenerator().StoreAccount(info.ID, password)
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
account := &accounts.Account{
|
// Imports a new mnemonic and creates local keystore file.
|
||||||
Address: types.Address(common.HexToAddress(info.Address)),
|
func (api *API) ImportMnemonic(ctx context.Context, mnemonic string, password string) error {
|
||||||
KeyUID: info.KeyUID,
|
|
||||||
PublicKey: types.HexBytes(info.PublicKey),
|
|
||||||
Type: accounts.AccountTypeKey,
|
|
||||||
Name: name,
|
|
||||||
Emoji: emoji,
|
|
||||||
Color: color,
|
|
||||||
Path: pathDefaultWallet,
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.SaveAccounts(ctx, []*accounts.Account{account})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) AddAccountWithPrivateKey(
|
|
||||||
ctx context.Context,
|
|
||||||
privateKey string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
) error {
|
|
||||||
err := api.verifyPassword(password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.AddAccountWithPrivateKeyPasswordVerified(ctx, privateKey, password, name, color, emoji)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) GenerateAccount(
|
|
||||||
ctx context.Context,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
) error {
|
|
||||||
address, err := api.db.GetWalletRootAddress()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
latestDerivedPath, err := api.db.GetLatestDerivedPath()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newDerivedPath := latestDerivedPath + 1
|
|
||||||
path := fmt.Sprint(pathWalletRoot, "/", newDerivedPath)
|
|
||||||
|
|
||||||
err = api.generateAccount(ctx, password, name, color, emoji, path, address.Hex())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = api.db.SaveSettingField(settings.LatestDerivedPath, newDerivedPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) GenerateAccountPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
) error {
|
|
||||||
address, err := api.db.GetWalletRootAddress()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
latestDerivedPath, err := api.db.GetLatestDerivedPath()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newDerivedPath := latestDerivedPath + 1
|
|
||||||
path := fmt.Sprint(pathWalletRoot, "/", newDerivedPath)
|
|
||||||
|
|
||||||
err = api.generateAccountPasswordVerified(ctx, password, name, color, emoji, path, address.Hex())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = api.db.SaveSettingField(settings.LatestDerivedPath, newDerivedPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) GenerateAccountWithDerivedPath(
|
|
||||||
ctx context.Context,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
derivedFrom string,
|
|
||||||
) error {
|
|
||||||
return api.generateAccount(ctx, password, name, color, emoji, path, derivedFrom)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) GenerateAccountWithDerivedPathPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
derivedFrom string,
|
|
||||||
) error {
|
|
||||||
return api.generateAccountPasswordVerified(ctx, password, name, color, emoji, path, derivedFrom)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) verifyPassword(password string) error {
|
|
||||||
address, err := api.db.GetChatAddress()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = api.manager.VerifyAccountPassword(api.config.KeyStoreDir, address.Hex(), password)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// addAccountWithMnemonicPasswordVerified adds an accounts.Account derived from the given Mnemonic
|
|
||||||
// assuming that client has already authenticated logged in use, this function doesn't verify a password.
|
|
||||||
func (api *API) addAccountWithMnemonicPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
mnemonic string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
) error {
|
|
||||||
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
|
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
|
||||||
|
|
||||||
generatedAccountInfo, err := api.manager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
|
generatedAccountInfo, err := api.manager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
|
||||||
|
@ -338,120 +201,25 @@ func (api *API) addAccountWithMnemonicPasswordVerified(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accs, err := api.db.GetAccountsByKeyUID(generatedAccountInfo.KeyUID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(accs) > 0 {
|
||||||
|
return errors.New("provided mnemonic was already imported, to add new account use `AddAccount` endpoint")
|
||||||
|
}
|
||||||
|
|
||||||
_, err = api.manager.AccountsGenerator().StoreAccount(generatedAccountInfo.ID, password)
|
_, err = api.manager.AccountsGenerator().StoreAccount(generatedAccountInfo.ID, password)
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
accountinfos, err := api.manager.AccountsGenerator().StoreDerivedAccounts(generatedAccountInfo.ID, password, []string{path})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
account := &accounts.Account{
|
|
||||||
Address: types.Address(common.HexToAddress(accountinfos[path].Address)),
|
|
||||||
KeyUID: generatedAccountInfo.KeyUID,
|
|
||||||
PublicKey: types.HexBytes(accountinfos[path].PublicKey),
|
|
||||||
Type: accounts.AccountTypeSeed,
|
|
||||||
Name: name,
|
|
||||||
Emoji: emoji,
|
|
||||||
Color: color,
|
|
||||||
Path: path,
|
|
||||||
DerivedFrom: generatedAccountInfo.Address,
|
|
||||||
}
|
|
||||||
return api.SaveAccounts(ctx, []*accounts.Account{account})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) addAccountWithMnemonic(
|
|
||||||
ctx context.Context,
|
|
||||||
mnemonic string,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
) error {
|
|
||||||
err := api.verifyPassword(password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.addAccountWithMnemonicPasswordVerified(ctx, mnemonic, password, name, color, emoji, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateAccountPasswordVerified adds an accounts.Account generated from the given path
|
|
||||||
// assuming that client has already authenticated logged in use, this function doesn't verify a password.
|
|
||||||
func (api *API) generateAccountPasswordVerified(
|
|
||||||
ctx context.Context,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
address string,
|
|
||||||
) error {
|
|
||||||
info, err := api.manager.AccountsGenerator().LoadAccount(address, password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
infos, err := api.manager.AccountsGenerator().DeriveAddresses(info.ID, []string{path})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = api.manager.AccountsGenerator().StoreDerivedAccounts(info.ID, password, []string{path})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
allAccounts, err := api.GetAccounts(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
accountType := accounts.AccountTypeGenerated
|
|
||||||
for _, acc := range allAccounts {
|
|
||||||
if (acc.Type == accounts.AccountTypeSeed || acc.Type == accounts.AccountTypeKey) && acc.DerivedFrom == address {
|
|
||||||
accountType = acc.Type
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
acc := &accounts.Account{
|
|
||||||
Address: types.Address(common.HexToAddress(infos[path].Address)),
|
|
||||||
KeyUID: info.KeyUID,
|
|
||||||
PublicKey: types.HexBytes(infos[path].PublicKey),
|
|
||||||
Type: accountType,
|
|
||||||
Name: name,
|
|
||||||
Emoji: emoji,
|
|
||||||
Color: color,
|
|
||||||
Path: path,
|
|
||||||
DerivedFrom: address,
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.SaveAccounts(ctx, []*accounts.Account{acc})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) generateAccount(
|
|
||||||
ctx context.Context,
|
|
||||||
password string,
|
|
||||||
name string,
|
|
||||||
color string,
|
|
||||||
emoji string,
|
|
||||||
path string,
|
|
||||||
address string,
|
|
||||||
) error {
|
|
||||||
err := api.verifyPassword(password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.generateAccountPasswordVerified(ctx, password, name, color, emoji, path, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) VerifyPassword(password string) bool {
|
func (api *API) VerifyPassword(password string) bool {
|
||||||
err := api.verifyPassword(password)
|
address, err := api.db.GetChatAddress()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = api.manager.VerifyAccountPassword(api.config.KeyStoreDir, address.Hex(), password)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -13,7 +12,6 @@ import (
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/rpc/chain"
|
"github.com/status-im/status-go/rpc/chain"
|
||||||
"github.com/status-im/status-go/services/wallet/async"
|
|
||||||
"github.com/status-im/status-go/services/wallet/bridge"
|
"github.com/status-im/status-go/services/wallet/bridge"
|
||||||
"github.com/status-im/status-go/services/wallet/currency"
|
"github.com/status-im/status-go/services/wallet/currency"
|
||||||
"github.com/status-im/status-go/services/wallet/history"
|
"github.com/status-im/status-go/services/wallet/history"
|
||||||
|
@ -393,25 +391,18 @@ func (api *API) GetSuggestedRoutes(
|
||||||
return api.router.suggestedRoutes(ctx, sendType, account, amountIn.ToInt(), tokenSymbol, disabledFromChainIDs, disabledToChaindIDs, preferedChainIDs, gasFeeMode, fromLockedAmount)
|
return api.router.suggestedRoutes(ctx, sendType, account, amountIn.ToInt(), tokenSymbol, disabledFromChainIDs, disabledToChaindIDs, preferedChainIDs, gasFeeMode, fromLockedAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) GetDerivedAddressForPath(ctx context.Context, password string, derivedFrom string, path string) (*DerivedAddress, error) {
|
// Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
|
||||||
|
func (api *API) GetDerivedAddresses(ctx context.Context, password string, derivedFrom string, paths []string) ([]*DerivedAddress, error) {
|
||||||
info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.getDerivedAddress(info.ID, path)
|
return api.getDerivedAddresses(info.ID, paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) GetDerivedAddressesForPath(ctx context.Context, password string, derivedFrom string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
// Generates addresses for the provided paths derived from the provided mnemonic, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
|
||||||
info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
func (api *API) GetDerivedAddressesForMnemonic(ctx context.Context, mnemonic string, paths []string) ([]*DerivedAddress, error) {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.getDerivedAddresses(ctx, info.ID, path, pageSize, pageNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) GetDerivedAddressesForMnemonicWithPath(ctx context.Context, mnemonic string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
|
||||||
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
|
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
|
||||||
|
|
||||||
info, err := api.s.gethManager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
|
info, err := api.s.gethManager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
|
||||||
|
@ -419,27 +410,44 @@ func (api *API) GetDerivedAddressesForMnemonicWithPath(ctx context.Context, mnem
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.getDerivedAddresses(ctx, info.ID, path, pageSize, pageNumber)
|
return api.getDerivedAddresses(info.ID, paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) GetDerivedAddressForPrivateKey(ctx context.Context, privateKey string) ([]*DerivedAddress, error) {
|
// Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
|
||||||
var derivedAddresses = make([]*DerivedAddress, 0)
|
func (api *API) getDerivedAddresses(id string, paths []string) ([]*DerivedAddress, error) {
|
||||||
info, err := api.s.gethManager.AccountsGenerator().ImportPrivateKey(privateKey)
|
addedAccounts, err := api.s.accountsDB.GetAccounts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return derivedAddresses, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
derivedAddress, err := api.GetDerivedAddressDetails(ctx, info.Address)
|
info, err := api.s.gethManager.AccountsGenerator().DeriveAddresses(id, paths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return derivedAddresses, err
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
derivedAddresses := make([]*DerivedAddress, 0)
|
||||||
|
for accPath, acc := range info {
|
||||||
|
|
||||||
|
derivedAddress := &DerivedAddress{
|
||||||
|
Address: common.HexToAddress(acc.Address),
|
||||||
|
Path: accPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, account := range addedAccounts {
|
||||||
|
if types.Address(derivedAddress.Address) == account.Address {
|
||||||
|
derivedAddress.AlreadyCreated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
derivedAddresses = append(derivedAddresses, derivedAddress)
|
derivedAddresses = append(derivedAddresses, derivedAddress)
|
||||||
|
}
|
||||||
|
|
||||||
return derivedAddresses, nil
|
return derivedAddresses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) GetDerivedAddressDetails(ctx context.Context, address string) (*DerivedAddress, error) {
|
// Returns details for the passed address (response doesn't include derivation path)
|
||||||
|
func (api *API) GetAddressDetails(ctx context.Context, address string) (*DerivedAddress, error) {
|
||||||
var derivedAddress *DerivedAddress
|
var derivedAddress *DerivedAddress
|
||||||
|
|
||||||
commonAddr := common.HexToAddress(address)
|
commonAddr := common.HexToAddress(address)
|
||||||
|
@ -447,9 +455,6 @@ func (api *API) GetDerivedAddressDetails(ctx context.Context, address string) (*
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return derivedAddress, err
|
return derivedAddress, err
|
||||||
}
|
}
|
||||||
if addressExists {
|
|
||||||
return derivedAddress, fmt.Errorf("account already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions, err := api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, commonAddr, nil, 1, false)
|
transactions, err := api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, commonAddr, nil, 1, false)
|
||||||
|
|
||||||
|
@ -469,93 +474,6 @@ func (api *API) GetDerivedAddressDetails(ctx context.Context, address string) (*
|
||||||
return derivedAddress, nil
|
return derivedAddress, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) getDerivedAddresses(ctx context.Context, id string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
|
||||||
var (
|
|
||||||
group = async.NewAtomicGroup(ctx)
|
|
||||||
derivedAddresses = make([]*DerivedAddress, 0)
|
|
||||||
unorderedDerivedAddresses = map[int]*DerivedAddress{}
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
splitPathValues := strings.Split(path, "/")
|
|
||||||
if len(splitPathValues) == 6 {
|
|
||||||
derivedAddress, err := api.getDerivedAddress(id, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
derivedAddresses = append(derivedAddresses, derivedAddress)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if pageNumber <= 0 || pageSize <= 0 {
|
|
||||||
return nil, fmt.Errorf("pageSize and pageNumber should be greater than 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
var startIndex = ((pageNumber - 1) * pageSize)
|
|
||||||
var endIndex = (pageNumber * pageSize)
|
|
||||||
|
|
||||||
for i := startIndex; i < endIndex; i++ {
|
|
||||||
derivedPath := fmt.Sprint(path, "/", i)
|
|
||||||
index := i
|
|
||||||
group.Add(func(parent context.Context) error {
|
|
||||||
derivedAddress, err := api.getDerivedAddress(id, derivedPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
unorderedDerivedAddresses[index] = derivedAddress
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-group.WaitAsync():
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
}
|
|
||||||
for i := startIndex; i < endIndex; i++ {
|
|
||||||
derivedAddresses = append(derivedAddresses, unorderedDerivedAddresses[i])
|
|
||||||
}
|
|
||||||
err = group.Error()
|
|
||||||
}
|
|
||||||
return derivedAddresses, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) getDerivedAddress(id string, derivedPath string) (*DerivedAddress, error) {
|
|
||||||
addedAccounts, err := api.s.accountsDB.GetAccounts()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := api.s.gethManager.AccountsGenerator().DeriveAddresses(id, []string{derivedPath})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
alreadyExists := false
|
|
||||||
for _, account := range addedAccounts {
|
|
||||||
if types.Address(common.HexToAddress(info[derivedPath].Address)) == account.Address {
|
|
||||||
alreadyExists = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var ctx context.Context
|
|
||||||
transactions, err := api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, common.HexToAddress(info[derivedPath].Address), nil, 1, false)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hasActivity := int64(len(transactions)) > 0
|
|
||||||
|
|
||||||
address := &DerivedAddress{
|
|
||||||
Address: common.HexToAddress(info[derivedPath].Address),
|
|
||||||
Path: derivedPath,
|
|
||||||
HasActivity: hasActivity,
|
|
||||||
AlreadyCreated: alreadyExists,
|
|
||||||
}
|
|
||||||
|
|
||||||
return address, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) CreateMultiTransaction(ctx context.Context, multiTransaction *transfer.MultiTransaction, data []*bridge.TransactionBridge, password string) (*transfer.MultiTransactionResult, error) {
|
func (api *API) CreateMultiTransaction(ctx context.Context, multiTransaction *transfer.MultiTransaction, data []*bridge.TransactionBridge, password string) (*transfer.MultiTransactionResult, error) {
|
||||||
log.Debug("[WalletAPI:: CreateMultiTransaction] create multi transaction")
|
log.Debug("[WalletAPI:: CreateMultiTransaction] create multi transaction")
|
||||||
return api.s.transactionManager.CreateMultiTransaction(ctx, multiTransaction, data, api.router.bridges, password)
|
return api.s.transactionManager.CreateMultiTransaction(ctx, multiTransaction, data, api.router.bridges, password)
|
||||||
|
|
Loading…
Reference in New Issue