2023-10-30 16:58:57 +00:00
|
|
|
package walletconnect
|
|
|
|
|
|
|
|
import (
|
2023-11-06 19:04:42 +00:00
|
|
|
"fmt"
|
|
|
|
|
2023-11-17 15:28:37 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
2023-10-30 16:58:57 +00:00
|
|
|
"github.com/ethereum/go-ethereum/event"
|
2023-11-06 19:04:42 +00:00
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
|
|
"github.com/status-im/status-go/account"
|
2023-11-17 15:28:37 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2023-10-30 16:58:57 +00:00
|
|
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
2023-11-06 19:04:42 +00:00
|
|
|
"github.com/status-im/status-go/params"
|
2023-10-30 16:58:57 +00:00
|
|
|
"github.com/status-im/status-go/rpc/network"
|
2023-11-06 19:04:42 +00:00
|
|
|
"github.com/status-im/status-go/transactions"
|
2023-10-30 16:58:57 +00:00
|
|
|
)
|
|
|
|
|
2023-11-17 15:28:37 +00:00
|
|
|
type txSigningDetails struct {
|
|
|
|
chainID uint64
|
|
|
|
from common.Address
|
|
|
|
txBeingSigned *ethTypes.Transaction
|
|
|
|
}
|
|
|
|
|
2023-10-30 16:58:57 +00:00
|
|
|
type Service struct {
|
|
|
|
networkManager *network.Manager
|
|
|
|
accountsDB *accounts.Database
|
|
|
|
eventFeed *event.Feed
|
2023-11-06 19:04:42 +00:00
|
|
|
|
|
|
|
transactor *transactions.Transactor
|
|
|
|
gethManager *account.GethManager
|
2023-11-17 15:28:37 +00:00
|
|
|
|
|
|
|
config *params.NodeConfig
|
|
|
|
txSignDetails *txSigningDetails
|
2023-10-30 16:58:57 +00:00
|
|
|
}
|
|
|
|
|
2023-11-17 15:28:37 +00:00
|
|
|
func NewService(networkManager *network.Manager, accountsDB *accounts.Database, transactor *transactions.Transactor,
|
|
|
|
gethManager *account.GethManager, eventFeed *event.Feed, config *params.NodeConfig) *Service {
|
2023-10-30 16:58:57 +00:00
|
|
|
return &Service{
|
|
|
|
networkManager: networkManager,
|
|
|
|
accountsDB: accountsDB,
|
|
|
|
eventFeed: eventFeed,
|
2023-11-06 19:04:42 +00:00
|
|
|
transactor: transactor,
|
|
|
|
gethManager: gethManager,
|
2023-11-17 15:28:37 +00:00
|
|
|
config: config,
|
2023-10-30 16:58:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-17 15:28:37 +00:00
|
|
|
func (s *Service) SignMessage(message types.HexBytes, address common.Address, password string) (string, error) {
|
|
|
|
selectedAccount, err := s.gethManager.VerifyAccountPassword(s.config.KeyStoreDir, address.Hex(), password)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
signature, err := crypto.Sign(message[:], selectedAccount.PrivateKey)
|
|
|
|
|
|
|
|
return types.EncodeHex(signature), err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) SendTransaction(signature string) (response *SessionRequestResponse, err error) {
|
|
|
|
return s.sendTransaction(signature)
|
|
|
|
}
|
|
|
|
|
2023-10-30 16:58:57 +00:00
|
|
|
func (s *Service) PairSessionProposal(proposal SessionProposal) (*PairSessionResponse, error) {
|
|
|
|
namespace := Namespace{
|
2023-11-06 19:04:42 +00:00
|
|
|
Methods: []string{params.SendTransactionMethodName, params.PersonalSignMethodName},
|
2023-10-30 16:58:57 +00:00
|
|
|
Events: []string{"accountsChanged", "chainChanged"},
|
|
|
|
}
|
|
|
|
|
|
|
|
proposedChains := proposal.Params.RequiredNamespaces.Eip155.Chains
|
|
|
|
chains, eipChains := sessionProposalToSupportedChain(proposedChains, func(chainID uint64) bool {
|
|
|
|
return s.networkManager.Find(chainID) != nil
|
|
|
|
})
|
|
|
|
if len(chains) != len(proposedChains) {
|
2023-11-06 19:04:42 +00:00
|
|
|
log.Warn("Some chains are not supported; wanted: ", proposedChains, "; supported: ", chains)
|
2023-10-30 16:58:57 +00:00
|
|
|
return nil, ErrorChainsNotSupported
|
|
|
|
}
|
|
|
|
namespace.Chains = eipChains
|
|
|
|
|
|
|
|
activeAccounts, err := s.accountsDB.GetActiveAccounts()
|
|
|
|
if err != nil {
|
2023-11-06 19:04:42 +00:00
|
|
|
return nil, fmt.Errorf("failed to get active accounts: %w", err)
|
2023-10-30 16:58:57 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 19:04:42 +00:00
|
|
|
// Filter out non-own accounts
|
|
|
|
usableAccounts := make([]*accounts.Account, 0, 1)
|
|
|
|
for _, acc := range activeAccounts {
|
2023-11-17 15:28:37 +00:00
|
|
|
if !acc.IsWalletAccountReadyForTransaction() {
|
2023-11-06 19:04:42 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
usableAccounts = append(usableAccounts, acc)
|
|
|
|
}
|
|
|
|
|
|
|
|
addresses := activeToOwnedAccounts(usableAccounts)
|
2023-10-30 16:58:57 +00:00
|
|
|
namespace.Accounts = caip10Accounts(addresses, chains)
|
|
|
|
|
|
|
|
// TODO #12434: respond async
|
|
|
|
return &PairSessionResponse{
|
|
|
|
SessionProposal: proposal,
|
|
|
|
SupportedNamespaces: Namespaces{
|
|
|
|
Eip155: namespace,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
2023-11-06 19:04:42 +00:00
|
|
|
|
2023-11-17 15:28:37 +00:00
|
|
|
func (s *Service) SessionRequest(request SessionRequest) (response *SessionRequestResponse, err error) {
|
2023-11-06 19:04:42 +00:00
|
|
|
// TODO #12434: should we check topic for validity? It might make sense if we
|
|
|
|
// want to cache the paired sessions
|
|
|
|
|
|
|
|
if request.Params.Request.Method == params.SendTransactionMethodName {
|
2023-11-17 15:28:37 +00:00
|
|
|
return s.buildTransaction(request)
|
2023-11-06 19:04:42 +00:00
|
|
|
} else if request.Params.Request.Method == params.PersonalSignMethodName {
|
2023-11-17 15:28:37 +00:00
|
|
|
return s.buildPersonalSingMessage(request)
|
2023-11-06 19:04:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO #12434: respond async
|
|
|
|
return nil, ErrorMethodNotSupported
|
|
|
|
}
|