feat(walletconnect)_: support for session proposal for wc 2.0
This commit is contained in:
parent
e32c5546e1
commit
d4ca8616fc
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -26,18 +27,19 @@ import (
|
|||
// log.Debug("wallet.api.wc RESPONSE", "eventType", eventType, "error", err, "payload.len", len(payload), "sentCount", sentCount)
|
||||
// }
|
||||
|
||||
func parseCaip2ChainID(str string) (uint64, error) {
|
||||
// Returns namspace name, chainID and error
|
||||
func parseCaip2ChainID(str string) (string, uint64, error) {
|
||||
caip2 := strings.Split(str, ":")
|
||||
if len(caip2) != 2 {
|
||||
return 0, errors.New("CAIP-2 string is not valid")
|
||||
return "", 0, errors.New("CAIP-2 string is not valid")
|
||||
}
|
||||
|
||||
chainIDStr := caip2[1]
|
||||
chainID, err := strconv.ParseUint(chainIDStr, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("CAIP-2 second value not valid Chain ID: %w", err)
|
||||
return "", 0, fmt.Errorf("CAIP-2 second value not valid Chain ID: %w", err)
|
||||
}
|
||||
return chainID, nil
|
||||
return caip2[0], chainID, nil
|
||||
}
|
||||
|
||||
// JSONProxyType provides a generic way of changing the JSON value before unmarshalling it into the target.
|
||||
|
@ -59,3 +61,11 @@ func (b *JSONProxyType) UnmarshalJSON(input []byte) error {
|
|||
|
||||
return json.Unmarshal(output, b.target)
|
||||
}
|
||||
|
||||
func isValidNamespaceName(namespaceName string) bool {
|
||||
pattern := "^[a-z0-9-]{3,8}$"
|
||||
|
||||
regex := regexp.MustCompile(pattern)
|
||||
|
||||
return regex.MatchString(namespaceName)
|
||||
}
|
||||
|
|
|
@ -1,60 +1,66 @@
|
|||
package walletconnect
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseCaip2ChainID(t *testing.T) {
|
||||
func Test_parseCaip2(t *testing.T) {
|
||||
type args struct {
|
||||
str string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want uint64
|
||||
wantErr bool
|
||||
name string
|
||||
args args
|
||||
wantChain uint64
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
args: args{
|
||||
str: "eip155:5",
|
||||
},
|
||||
want: 5,
|
||||
wantErr: false,
|
||||
wantChain: 5,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid_number",
|
||||
args: args{
|
||||
str: "eip155:5a",
|
||||
},
|
||||
want: 0,
|
||||
wantErr: true,
|
||||
wantChain: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid_caip2_too_many",
|
||||
args: args{
|
||||
str: "eip155:1:5",
|
||||
},
|
||||
want: 0,
|
||||
wantErr: true,
|
||||
wantChain: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid_caip2_not_enough",
|
||||
args: args{
|
||||
str: "eip1551",
|
||||
},
|
||||
want: 0,
|
||||
wantErr: true,
|
||||
wantChain: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseCaip2ChainID(tt.args.str)
|
||||
gotNamespaceName, gotChainID, err := parseCaip2ChainID(tt.args.str)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseCaip2ChainID() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("parseCaip2ChainID() = %v, want %v", got, tt.want)
|
||||
if !tt.wantErr && !strings.Contains(tt.args.str, gotNamespaceName) {
|
||||
t.Errorf("parseCaip2ChainID() = %v, doesn't match %v", gotNamespaceName, tt.args.str)
|
||||
}
|
||||
if gotChainID != tt.wantChain {
|
||||
t.Errorf("parseCaip2ChainID() = %v, want %v", gotChainID, tt.wantChain)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ func (s *Service) buildTransaction(request SessionRequest) (response *SessionReq
|
|||
return nil, err
|
||||
}
|
||||
|
||||
chainID, err := parseCaip2ChainID(request.Params.ChainID)
|
||||
_, chainID, err := parseCaip2ChainID(request.Params.ChainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package walletconnect
|
|||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
@ -66,45 +67,79 @@ func (s *Service) SendTransaction(signature string) (response *SessionRequestRes
|
|||
}
|
||||
|
||||
func (s *Service) PairSessionProposal(proposal SessionProposal) (*PairSessionResponse, error) {
|
||||
namespace := Namespace{
|
||||
Methods: []string{params.SendTransactionMethodName, params.PersonalSignMethodName},
|
||||
Events: []string{"accountsChanged", "chainChanged"},
|
||||
if !proposal.Valid() {
|
||||
return nil, ErrorInvalidSessionProposal
|
||||
}
|
||||
|
||||
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) {
|
||||
log.Warn("Some chains are not supported; wanted: ", proposedChains, "; supported: ", chains)
|
||||
return nil, ErrorChainsNotSupported
|
||||
var (
|
||||
chains []uint64
|
||||
eipChains []string
|
||||
)
|
||||
|
||||
if len(proposal.Params.RequiredNamespaces) == 0 {
|
||||
// return all we support
|
||||
allChains, err := s.networkManager.GetAll()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get all chains: %w", err)
|
||||
}
|
||||
for _, chain := range allChains {
|
||||
chains = append(chains, chain.ChainID)
|
||||
eipChains = append(eipChains, fmt.Sprintf("%s:%d", SupportedEip155Namespace, chain.ChainID))
|
||||
}
|
||||
} else {
|
||||
var proposedChains []string
|
||||
for key, ns := range proposal.Params.RequiredNamespaces {
|
||||
if !strings.Contains(key, SupportedEip155Namespace) {
|
||||
log.Warn("Some namespaces are not supported; wanted: ", key, "; supported: ", SupportedEip155Namespace)
|
||||
return nil, ErrorNamespaceNotSupported
|
||||
}
|
||||
|
||||
if strings.Contains(key, ":") {
|
||||
proposedChains = append(proposedChains, key)
|
||||
} else {
|
||||
proposedChains = append(proposedChains, ns.Chains...)
|
||||
}
|
||||
}
|
||||
|
||||
chains, eipChains = sessionProposalToSupportedChain(proposedChains, func(chainID uint64) bool {
|
||||
return s.networkManager.Find(chainID) != nil
|
||||
})
|
||||
|
||||
if len(chains) != len(proposedChains) {
|
||||
log.Warn("Some chains are not supported; wanted: ", proposedChains, "; supported: ", chains)
|
||||
return nil, ErrorChainsNotSupported
|
||||
}
|
||||
}
|
||||
namespace.Chains = eipChains
|
||||
|
||||
activeAccounts, err := s.accountsDB.GetActiveAccounts()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get active accounts: %w", err)
|
||||
}
|
||||
|
||||
// Filter out non-own accounts
|
||||
usableAccounts := make([]*accounts.Account, 0, 1)
|
||||
allWalletAccountsReadyForTransaction := make([]*accounts.Account, 0, 1)
|
||||
for _, acc := range activeAccounts {
|
||||
if !acc.IsWalletAccountReadyForTransaction() {
|
||||
continue
|
||||
}
|
||||
usableAccounts = append(usableAccounts, acc)
|
||||
allWalletAccountsReadyForTransaction = append(allWalletAccountsReadyForTransaction, acc)
|
||||
}
|
||||
|
||||
addresses := activeToOwnedAccounts(usableAccounts)
|
||||
namespace.Accounts = caip10Accounts(addresses, chains)
|
||||
result := &PairSessionResponse{
|
||||
SessionProposal: proposal,
|
||||
SupportedNamespaces: map[string]Namespace{
|
||||
SupportedEip155Namespace: Namespace{
|
||||
Methods: []string{params.SendTransactionMethodName,
|
||||
params.PersonalSignMethodName,
|
||||
},
|
||||
Events: []string{"accountsChanged", "chainChanged"},
|
||||
Chains: eipChains,
|
||||
Accounts: caip10Accounts(allWalletAccountsReadyForTransaction, chains),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// TODO #12434: respond async
|
||||
return &PairSessionResponse{
|
||||
SessionProposal: proposal,
|
||||
SupportedNamespaces: Namespaces{
|
||||
Eip155: namespace,
|
||||
},
|
||||
}, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Service) RecordSuccessfulPairing(proposal SessionProposal) error {
|
||||
|
|
|
@ -3,7 +3,9 @@ package walletconnect
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
|
@ -12,11 +14,20 @@ import (
|
|||
"github.com/status-im/status-go/services/wallet/walletevent"
|
||||
)
|
||||
|
||||
const ProposeUserPairEvent = walletevent.EventType("WalletConnectProposeUserPair")
|
||||
const (
|
||||
SupportedEip155Namespace = "eip155"
|
||||
|
||||
var ErrorChainsNotSupported = errors.New("chains not supported")
|
||||
var ErrorInvalidParamsCount = errors.New("invalid params count")
|
||||
var ErrorMethodNotSupported = errors.New("method not supported")
|
||||
ProposeUserPairEvent = walletevent.EventType("WalletConnectProposeUserPair")
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorInvalidSessionProposal = errors.New("invalid session proposal")
|
||||
ErrorNamespaceNotSupported = errors.New("namespace not supported")
|
||||
ErrorChainsNotSupported = errors.New("chains not supported")
|
||||
ErrorInvalidParamsCount = errors.New("invalid params count")
|
||||
ErrorInvalidAddressMsgIndex = errors.New("invalid address and/or msg index (must be 0 or 1)")
|
||||
ErrorMethodNotSupported = errors.New("method not supported")
|
||||
)
|
||||
|
||||
type Topic string
|
||||
|
||||
|
@ -40,11 +51,6 @@ type Proposer struct {
|
|||
Metadata Metadata `json:"metadata"`
|
||||
}
|
||||
|
||||
type Namespaces struct {
|
||||
Eip155 Namespace `json:"eip155"`
|
||||
// We ignore non ethereum namespaces
|
||||
}
|
||||
|
||||
type Verified struct {
|
||||
VerifyURL string `json:"verifyUrl"`
|
||||
Validation string `json:"validation"`
|
||||
|
@ -57,13 +63,13 @@ type VerifyContext struct {
|
|||
}
|
||||
|
||||
type Params struct {
|
||||
ID int64 `json:"id"`
|
||||
PairingTopic Topic `json:"pairingTopic"`
|
||||
Expiry int64 `json:"expiry"`
|
||||
RequiredNamespaces Namespaces `json:"requiredNamespaces"`
|
||||
OptionalNamespaces Namespaces `json:"optionalNamespaces"`
|
||||
Proposer Proposer `json:"proposer"`
|
||||
Verify VerifyContext `json:"verifyContext"`
|
||||
ID int64 `json:"id"`
|
||||
PairingTopic Topic `json:"pairingTopic"`
|
||||
Expiry int64 `json:"expiry"`
|
||||
RequiredNamespaces map[string]Namespace `json:"requiredNamespaces"`
|
||||
OptionalNamespaces map[string]Namespace `json:"optionalNamespaces"`
|
||||
Proposer Proposer `json:"proposer"`
|
||||
Verify VerifyContext `json:"verifyContext"`
|
||||
}
|
||||
|
||||
type SessionProposal struct {
|
||||
|
@ -72,8 +78,8 @@ type SessionProposal struct {
|
|||
}
|
||||
|
||||
type PairSessionResponse struct {
|
||||
SessionProposal SessionProposal `json:"sessionProposal"`
|
||||
SupportedNamespaces Namespaces `json:"supportedNamespaces"`
|
||||
SessionProposal SessionProposal `json:"sessionProposal"`
|
||||
SupportedNamespaces map[string]Namespace `json:"supportedNamespaces"`
|
||||
}
|
||||
|
||||
type RequestParams struct {
|
||||
|
@ -105,11 +111,67 @@ type SessionRequestResponse struct {
|
|||
SignedMessage interface{} `json:"signedMessage,omitempty"`
|
||||
}
|
||||
|
||||
// Valid namespace
|
||||
func (n *Namespace) Valid(namespaceName string, chainID *uint64) bool {
|
||||
if chainID == nil {
|
||||
if len(n.Chains) == 0 {
|
||||
log.Warn("namespace doesn't refer to any chain")
|
||||
return false
|
||||
}
|
||||
for _, caip2Str := range n.Chains {
|
||||
resolvedNamespaceName, _, err := parseCaip2ChainID(caip2Str)
|
||||
if err != nil {
|
||||
log.Warn("namespace chain not in caip2 format", "chain", caip2Str, "error", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if resolvedNamespaceName != namespaceName {
|
||||
log.Warn("namespace name doesn't match", "namespace", namespaceName, "chain", caip2Str)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Valid params
|
||||
func (p *Params) Valid() bool {
|
||||
for key, ns := range p.RequiredNamespaces {
|
||||
var chainID *uint64
|
||||
if strings.Contains(key, ":") {
|
||||
resolvedNamespaceName, cID, err := parseCaip2ChainID(key)
|
||||
if err != nil {
|
||||
log.Warn("params validation failed CAIP-2", "str", key, "error", err)
|
||||
return false
|
||||
}
|
||||
key = resolvedNamespaceName
|
||||
chainID = &cID
|
||||
}
|
||||
|
||||
if !isValidNamespaceName(key) {
|
||||
log.Warn("invalid namespace name", "namespace", key)
|
||||
return false
|
||||
}
|
||||
|
||||
if !ns.Valid(key, chainID) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Valid session propsal
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#controller-side-validation-of-incoming-proposal-namespaces-wallet
|
||||
func (p *SessionProposal) Valid() bool {
|
||||
return p.Params.Valid()
|
||||
}
|
||||
|
||||
func sessionProposalToSupportedChain(caipChains []string, supportsChain func(uint64) bool) (chains []uint64, eipChains []string) {
|
||||
chains = make([]uint64, 0, 1)
|
||||
eipChains = make([]string, 0, 1)
|
||||
for _, caip2Str := range caipChains {
|
||||
chainID, err := parseCaip2ChainID(caip2Str)
|
||||
_, chainID, err := parseCaip2ChainID(caip2Str)
|
||||
if err != nil {
|
||||
log.Warn("Failed parsing CAIP-2", "str", caip2Str, "error", err)
|
||||
continue
|
||||
|
@ -125,22 +187,12 @@ func sessionProposalToSupportedChain(caipChains []string, supportsChain func(uin
|
|||
return
|
||||
}
|
||||
|
||||
func activeToOwnedAccounts(activeAccounts []*accounts.Account) []types.Address {
|
||||
addresses := make([]types.Address, 0, 1)
|
||||
for _, account := range activeAccounts {
|
||||
if account.Type != accounts.AccountTypeWatch {
|
||||
addresses = append(addresses, account.Address)
|
||||
func caip10Accounts(accounts []*accounts.Account, chains []uint64) []string {
|
||||
addresses := make([]string, 0, len(accounts)*len(chains))
|
||||
for _, acc := range accounts {
|
||||
for _, chainID := range chains {
|
||||
addresses = append(addresses, fmt.Sprintf("%s:%s:%s", SupportedEip155Namespace, strconv.FormatUint(chainID, 10), acc.Address.Hex()))
|
||||
}
|
||||
}
|
||||
return addresses
|
||||
}
|
||||
|
||||
func caip10Accounts(addresses []types.Address, chains []uint64) []string {
|
||||
accounts := make([]string, 0, len(addresses)*len(chains))
|
||||
for _, address := range addresses {
|
||||
for _, chainID := range chains {
|
||||
accounts = append(accounts, "eip155:"+strconv.FormatUint(chainID, 10)+":"+address.Hex())
|
||||
}
|
||||
}
|
||||
return accounts
|
||||
}
|
||||
|
|
|
@ -4,10 +4,194 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_sessionProposalValidity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sessionProposalJSON string
|
||||
expectedValidity bool
|
||||
}{
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#11-proposal-namespaces-does-not-include-an-optional-namespace
|
||||
{
|
||||
name: "proposal-namespaces-does-not-include-an-optional-namespace",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"eip155:10": {
|
||||
"methods": ["personal_sign"],
|
||||
"events": ["accountsChanged", "chainChanged"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: true,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#12-proposal-namespaces-must-not-have-chains-empty
|
||||
{
|
||||
name: "proposal-namespaces-must-not-have-chains-empty",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"cosmos": {
|
||||
"chains": [],
|
||||
"methods": ["cosmos_signDirect"],
|
||||
"events": ["someCosmosEvent"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: false,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#13-chains-might-be-omitted-if-the-caip-2-is-defined-in-the-index
|
||||
{
|
||||
name: "chains-might-be-omitted-if-the-caip-2-is-defined-in-the-index",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"eip155": {
|
||||
"chains": ["eip155:1", "eip155:137"],
|
||||
"methods": ["eth_sendTransaction", "eth_signTransaction", "eth_sign"],
|
||||
"events": ["accountsChanged", "chainChanged"]
|
||||
},
|
||||
"eip155:10": {
|
||||
"methods": ["personal_sign"],
|
||||
"events": ["accountsChanged", "chainChanged"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: true,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#14-chains-must-be-caip-2-compliant
|
||||
{
|
||||
name: "chains-must-be-caip-2-compliant",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"eip155": {
|
||||
"chains": ["42"],
|
||||
"methods": ["eth_sign"],
|
||||
"events": ["accountsChanged"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: false,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#15-proposal-namespace-methods-and-events-may-be-empty
|
||||
{
|
||||
name: "proposal-namespace-methods-and-events-may-be-empty",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"eip155": {
|
||||
"chains": ["eip155:1"],
|
||||
"methods": [],
|
||||
"events": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: true,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#16-all-chains-in-the-namespace-must-contain-the-namespace-prefix
|
||||
{
|
||||
name: "all-chains-in-the-namespace-must-contain-the-namespace-prefix",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"eip155": {
|
||||
"chains": ["eip155:1", "eip155:137", "cosmos:cosmoshub-4"],
|
||||
"methods": ["eth_sendTransaction"],
|
||||
"events": ["accountsChanged", "chainChanged"]
|
||||
}
|
||||
},
|
||||
"optionalNamespaces": {
|
||||
"eip155:42161": {
|
||||
"methods": ["personal_sign"],
|
||||
"events": ["accountsChanged", "chainChanged"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: false,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#17-namespace-key-must-comply-with-caip-2-specification
|
||||
{
|
||||
name: "namespace-key-must-comply-with-caip-2-specification",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"": {
|
||||
"chains": [":1"],
|
||||
"methods": ["personalSign"],
|
||||
"events": []
|
||||
},
|
||||
"**": {
|
||||
"chains": ["**:1"],
|
||||
"methods": ["personalSign"],
|
||||
"events": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: false,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#18-all-namespaces-must-be-valid
|
||||
{
|
||||
name: "all-namespaces-must-be-valid",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {
|
||||
"eip155": {
|
||||
"chains": ["eip155:1"],
|
||||
"methods": ["personalSign"],
|
||||
"events": []
|
||||
},
|
||||
"cosmos": {
|
||||
"chains": [],
|
||||
"methods": [],
|
||||
"events": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: false,
|
||||
},
|
||||
// https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#19-proposal-namespaces-may-be-empty
|
||||
{
|
||||
name: "proposal-namespaces-may-be-empty",
|
||||
sessionProposalJSON: `{
|
||||
"params": {
|
||||
"requiredNamespaces": {}
|
||||
}
|
||||
}`,
|
||||
expectedValidity: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var sessionProposal SessionProposal
|
||||
err := json.Unmarshal([]byte(tt.sessionProposalJSON), &sessionProposal)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if tt.expectedValidity {
|
||||
assert.True(t, sessionProposal.Valid())
|
||||
} else {
|
||||
assert.False(t, sessionProposal.Valid())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_sessionProposalToSupportedChain(t *testing.T) {
|
||||
type args struct {
|
||||
chains []string
|
||||
|
@ -66,52 +250,10 @@ func Test_sessionProposalToSupportedChain(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_activeToOwnedAccounts(t *testing.T) {
|
||||
type args struct {
|
||||
activeAccounts []*accounts.Account
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []types.Address
|
||||
}{
|
||||
{
|
||||
name: "filter_out_watch_accounts",
|
||||
args: args{
|
||||
activeAccounts: []*accounts.Account{
|
||||
{
|
||||
Address: types.HexToAddress("0x1"),
|
||||
Type: accounts.AccountTypeWatch,
|
||||
},
|
||||
{
|
||||
Address: types.HexToAddress("0x2"),
|
||||
Type: accounts.AccountTypeSeed,
|
||||
},
|
||||
{
|
||||
Address: types.HexToAddress("0x3"),
|
||||
Type: accounts.AccountTypeSeed,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.Address{
|
||||
types.HexToAddress("0x2"),
|
||||
types.HexToAddress("0x3"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := activeToOwnedAccounts(tt.args.activeAccounts); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("activeToOwnedAccounts() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_caip10Accounts(t *testing.T) {
|
||||
type args struct {
|
||||
addresses []types.Address
|
||||
chains []uint64
|
||||
accounts []*accounts.Account
|
||||
chains []uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -121,9 +263,15 @@ func Test_caip10Accounts(t *testing.T) {
|
|||
{
|
||||
name: "generate_caip10_accounts",
|
||||
args: args{
|
||||
addresses: []types.Address{
|
||||
types.HexToAddress("0x1"),
|
||||
types.HexToAddress("0x2"),
|
||||
accounts: []*accounts.Account{
|
||||
{
|
||||
Address: types.HexToAddress("0x1"),
|
||||
Type: accounts.AccountTypeWatch,
|
||||
},
|
||||
{
|
||||
Address: types.HexToAddress("0x2"),
|
||||
Type: accounts.AccountTypeSeed,
|
||||
},
|
||||
},
|
||||
chains: []uint64{1, 2},
|
||||
},
|
||||
|
@ -137,17 +285,23 @@ func Test_caip10Accounts(t *testing.T) {
|
|||
{
|
||||
name: "empty_addresses",
|
||||
args: args{
|
||||
addresses: []types.Address{},
|
||||
chains: []uint64{1, 2},
|
||||
accounts: []*accounts.Account{},
|
||||
chains: []uint64{1, 2},
|
||||
},
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
name: "empty_chains",
|
||||
args: args{
|
||||
addresses: []types.Address{
|
||||
types.HexToAddress("0x1"),
|
||||
types.HexToAddress("0x2"),
|
||||
accounts: []*accounts.Account{
|
||||
{
|
||||
Address: types.HexToAddress("0x1"),
|
||||
Type: accounts.AccountTypeWatch,
|
||||
},
|
||||
{
|
||||
Address: types.HexToAddress("0x2"),
|
||||
Type: accounts.AccountTypeSeed,
|
||||
},
|
||||
},
|
||||
chains: []uint64{},
|
||||
},
|
||||
|
@ -156,7 +310,7 @@ func Test_caip10Accounts(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := caip10Accounts(tt.args.addresses, tt.args.chains); !reflect.DeepEqual(got, tt.want) {
|
||||
if got := caip10Accounts(tt.args.accounts, tt.args.chains); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("caip10Accounts() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue