feat: Add hasActivity param to derived addresses (#2663)
Added functionality to find target address when 6th param in path is added for ex: "m'/44'/60'/0'/0/500" reperents the Address at the 500th index Added a api to get the Address derived from a private key
This commit is contained in:
parent
714c03c635
commit
15e5584ed2
|
@ -443,7 +443,7 @@ func (b *StatusNode) appmetricsService() common.StatusService {
|
|||
|
||||
func (b *StatusNode) walletService(accountsDB *accounts.Database, accountsFeed *event.Feed, openseaAPIKey string) common.StatusService {
|
||||
if b.walletSrvc == nil {
|
||||
b.walletSrvc = wallet.NewService(b.appDB, accountsDB, b.rpcClient, accountsFeed, openseaAPIKey)
|
||||
b.walletSrvc = wallet.NewService(b.appDB, accountsDB, b.rpcClient, accountsFeed, openseaAPIKey, b.gethAccountManager)
|
||||
}
|
||||
return b.walletSrvc
|
||||
}
|
||||
|
|
|
@ -32,13 +32,6 @@ type API struct {
|
|||
feed *event.Feed
|
||||
}
|
||||
|
||||
type DerivedAddress struct {
|
||||
Address common.Address `json:"address"`
|
||||
Path string `json:"path"`
|
||||
HasActivity bool `json:"hasActivity"`
|
||||
AlreadyCreated bool `json:"alreadyCreated"`
|
||||
}
|
||||
|
||||
func (api *API) SaveAccounts(ctx context.Context, accounts []accounts.Account) error {
|
||||
log.Info("[AccountsAPI::SaveAccounts]")
|
||||
err := api.db.SaveAccounts(accounts)
|
||||
|
@ -201,26 +194,6 @@ func (api *API) GenerateAccountWithDerivedPath(
|
|||
return api.generateAccount(ctx, password, name, color, emoji, path, derivedFrom)
|
||||
}
|
||||
|
||||
func (api *API) GetDerivedAddressesForPath(password string, derivedFrom string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
||||
info, err := api.manager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.getDerivedAddresses(info.ID, path, pageSize, pageNumber)
|
||||
}
|
||||
|
||||
func (api *API) GetDerivedAddressesForMenominicWithPath(mnemonic string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
||||
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
|
||||
|
||||
info, err := api.manager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.getDerivedAddresses(info.ID, path, pageSize, pageNumber)
|
||||
}
|
||||
|
||||
func (api *API) verifyPassword(password string) error {
|
||||
address, err := api.db.GetChatAddress()
|
||||
if err != nil {
|
||||
|
@ -230,49 +203,6 @@ func (api *API) verifyPassword(password string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (api *API) getDerivedAddresses(id string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
||||
addedAccounts, err := api.db.GetAccounts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
derivedAddresses := make([]*DerivedAddress, 0)
|
||||
|
||||
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)
|
||||
|
||||
info, err := api.manager.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
|
||||
}
|
||||
}
|
||||
|
||||
address := &DerivedAddress{
|
||||
Address: common.HexToAddress(info[derivedPath].Address),
|
||||
Path: derivedPath,
|
||||
HasActivity: false,
|
||||
AlreadyCreated: alreadyExists,
|
||||
}
|
||||
|
||||
derivedAddresses = append(derivedAddresses, address)
|
||||
}
|
||||
return derivedAddresses, nil
|
||||
}
|
||||
|
||||
func (api *API) addAccountWithMnemonic(
|
||||
ctx context.Context,
|
||||
mnemonic string,
|
||||
|
|
|
@ -2,11 +2,16 @@ package wallet
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/services/wallet/async"
|
||||
"github.com/status-im/status-go/services/wallet/chain"
|
||||
"github.com/status-im/status-go/services/wallet/transfer"
|
||||
)
|
||||
|
@ -30,6 +35,13 @@ func (api *API) GetWallet(ctx context.Context, chainIDs []uint64) (*Wallet, erro
|
|||
return api.r.GetWallet(ctx, chainIDs)
|
||||
}
|
||||
|
||||
type DerivedAddress struct {
|
||||
Address common.Address `json:"address"`
|
||||
Path string `json:"path"`
|
||||
HasActivity bool `json:"hasActivity"`
|
||||
AlreadyCreated bool `json:"alreadyCreated"`
|
||||
}
|
||||
|
||||
// SetInitialBlocksRange sets initial blocks range
|
||||
func (api *API) SetInitialBlocksRange(ctx context.Context) error {
|
||||
return api.s.transferController.SetInitialBlocksRange([]uint64{api.s.rpcClient.UpstreamChainID})
|
||||
|
@ -303,3 +315,144 @@ func (api *API) GetSuggestedFees(ctx context.Context, chainID uint64) (*Suggeste
|
|||
log.Debug("call to GetSuggestedFees")
|
||||
return api.s.feesManager.suggestedFees(ctx, chainID)
|
||||
}
|
||||
|
||||
func (api *API) GetDerivedAddressesForPath(ctx context.Context, password string, derivedFrom string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
||||
info, err := api.s.gethManager.AccountsGenerator().LoadAccount(derivedFrom, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.getDerivedAddresses(ctx, info.ID, path, pageSize, pageNumber)
|
||||
}
|
||||
|
||||
func (api *API) GetDerivedAddressesForMenominicWithPath(ctx context.Context, mnemonic string, path string, pageSize int, pageNumber int) ([]*DerivedAddress, error) {
|
||||
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
|
||||
|
||||
info, err := api.s.gethManager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.getDerivedAddresses(ctx, info.ID, path, pageSize, pageNumber)
|
||||
}
|
||||
|
||||
func (api *API) GetDerivedAddressForPrivateKey(ctx context.Context, privateKey string) ([]*DerivedAddress, error) {
|
||||
var derivedAddresses = make([]*DerivedAddress, 0)
|
||||
info, err := api.s.gethManager.AccountsGenerator().ImportPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return derivedAddresses, err
|
||||
}
|
||||
|
||||
addressExists, err := api.s.accountsDB.AddressExists(types.Address(common.HexToAddress(info.Address)))
|
||||
if err != nil {
|
||||
return derivedAddresses, err
|
||||
}
|
||||
if addressExists {
|
||||
return derivedAddresses, fmt.Errorf("account already exists")
|
||||
}
|
||||
|
||||
transactions, err := api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, common.HexToAddress(info.Address), nil, (*hexutil.Big)(big.NewInt(1)), false)
|
||||
|
||||
if err != nil {
|
||||
return derivedAddresses, err
|
||||
}
|
||||
|
||||
hasActivity := int64(len(transactions)) > 0
|
||||
|
||||
derivedAddress := &DerivedAddress{
|
||||
Address: common.HexToAddress(info.Address),
|
||||
Path: "",
|
||||
HasActivity: hasActivity,
|
||||
AlreadyCreated: addressExists,
|
||||
}
|
||||
derivedAddresses = append(derivedAddresses, derivedAddress)
|
||||
|
||||
return derivedAddresses, 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, (*hexutil.Big)(big.NewInt(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
|
||||
}
|
||||
|
|
|
@ -8,13 +8,14 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p"
|
||||
gethrpc "github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/status-im/status-go/account"
|
||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/wallet/transfer"
|
||||
)
|
||||
|
||||
// NewService initializes service instance.
|
||||
func NewService(db *sql.DB, accountsDB *accounts.Database, rpcClient *rpc.Client, accountFeed *event.Feed, openseaAPIKey string) *Service {
|
||||
func NewService(db *sql.DB, accountsDB *accounts.Database, rpcClient *rpc.Client, accountFeed *event.Feed, openseaAPIKey string, gethManager *account.GethManager) *Service {
|
||||
cryptoOnRampManager := NewCryptoOnRampManager(&CryptoOnRampOptions{
|
||||
dataSourceType: DataSourceStatic,
|
||||
})
|
||||
|
@ -36,6 +37,7 @@ func NewService(db *sql.DB, accountsDB *accounts.Database, rpcClient *rpc.Client
|
|||
cryptoOnRampManager: cryptoOnRampManager,
|
||||
openseaAPIKey: openseaAPIKey,
|
||||
feesManager: &FeeManager{rpcClient},
|
||||
gethManager: gethManager,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +55,7 @@ type Service struct {
|
|||
feesManager *FeeManager
|
||||
started bool
|
||||
openseaAPIKey string
|
||||
gethManager *account.GethManager
|
||||
}
|
||||
|
||||
// Start signals transmitter.
|
||||
|
|
Loading…
Reference in New Issue