github.com/status-im/status-go@v1.1.0/services/connector/connector_flows_test.go (about)

     1  package connector
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"github.com/status-im/status-go/eth-node/types"
    11  	"github.com/status-im/status-go/params"
    12  	"github.com/status-im/status-go/services/connector/chainutils"
    13  	"github.com/status-im/status-go/services/connector/commands"
    14  	walletCommon "github.com/status-im/status-go/services/wallet/common"
    15  	"github.com/status-im/status-go/signal"
    16  )
    17  
    18  func TestRequestAccountsSwitchChainAndSendTransactionFlow(t *testing.T) {
    19  	db, close := createDB(t)
    20  	defer close()
    21  
    22  	nm := commands.NetworkManagerMock{}
    23  	nm.SetNetworks([]*params.Network{
    24  		{
    25  			ChainID: walletCommon.EthereumMainnet,
    26  			Layer:   1,
    27  		},
    28  		{
    29  			ChainID: walletCommon.OptimismMainnet,
    30  			Layer:   1,
    31  		},
    32  	})
    33  	rpc := commands.RPCClientMock{}
    34  
    35  	service := NewService(db, &rpc, &nm)
    36  
    37  	api := NewAPI(service)
    38  
    39  	accountAddress := types.BytesToAddress(types.FromHex("0x6d0aa2a774b74bb1d36f97700315adf962c69fcg"))
    40  	expectedHash := types.BytesToHash(types.FromHex("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"))
    41  	expectedSignature := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
    42  
    43  	dAppPermissionRevoked := false
    44  	dAppPermissionGranted := false
    45  
    46  	signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
    47  		var evt commands.EventType
    48  		err := json.Unmarshal(s, &evt)
    49  		assert.NoError(t, err)
    50  
    51  		switch evt.Type {
    52  		case signal.EventConnectorDAppPermissionRevoked:
    53  			dAppPermissionRevoked = true
    54  		case signal.EventConnectorDAppPermissionGranted:
    55  			dAppPermissionGranted = true
    56  		case signal.EventConnectorSendRequestAccounts:
    57  			var ev signal.ConnectorSendRequestAccountsSignal
    58  			err := json.Unmarshal(evt.Event, &ev)
    59  			assert.NoError(t, err)
    60  
    61  			err = api.RequestAccountsAccepted(commands.RequestAccountsAcceptedArgs{
    62  				RequestID: ev.RequestID,
    63  				Account:   accountAddress,
    64  				ChainID:   0x1,
    65  			})
    66  			assert.NoError(t, err)
    67  		case signal.EventConnectorSendTransaction:
    68  			var ev signal.ConnectorSendTransactionSignal
    69  			err := json.Unmarshal(evt.Event, &ev)
    70  			assert.NoError(t, err)
    71  
    72  			err = api.SendTransactionAccepted(commands.SendTransactionAcceptedArgs{
    73  				RequestID: ev.RequestID,
    74  				Hash:      expectedHash,
    75  			})
    76  			assert.NoError(t, err)
    77  		case signal.EventConnectorPersonalSign:
    78  			var ev signal.ConnectorPersonalSignSignal
    79  			err := json.Unmarshal(evt.Event, &ev)
    80  			assert.NoError(t, err)
    81  
    82  			err = api.PersonalSignAccepted(commands.PersonalSignAcceptedArgs{
    83  				RequestID: ev.RequestID,
    84  				Signature: expectedSignature,
    85  			})
    86  			assert.NoError(t, err)
    87  		}
    88  	}))
    89  	t.Cleanup(signal.ResetMobileSignalHandler)
    90  
    91  	// Request accounts, now for real
    92  	request := "{\"method\": \"eth_requestAccounts\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
    93  	response, err := api.CallRPC(request)
    94  	assert.NoError(t, err)
    95  	assert.Equal(t, commands.FormatAccountAddressToResponse(accountAddress), response)
    96  	assert.Equal(t, true, dAppPermissionGranted)
    97  	assert.Equal(t, false, dAppPermissionRevoked)
    98  
    99  	// Request to switch ethereum chain
   100  	expectedChainID, err := chainutils.GetHexChainID(walletCommon.ChainID(walletCommon.EthereumMainnet).String())
   101  	assert.NoError(t, err)
   102  	request = fmt.Sprintf("{\"method\": \"wallet_switchEthereumChain\", \"params\": [{\"chainId\": \"%s\"}], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }", expectedChainID)
   103  	response, err = api.CallRPC(request)
   104  	assert.NoError(t, err)
   105  	assert.Equal(t, expectedChainID, response)
   106  
   107  	// Check if the chain was switched
   108  	request = "{\"method\": \"eth_chainId\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
   109  	response, err = api.CallRPC(request)
   110  	assert.NoError(t, err)
   111  	assert.Equal(t, expectedChainID, response)
   112  
   113  	// Check the account after switching chain
   114  	request = "{\"method\": \"eth_accounts\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
   115  	response, err = api.CallRPC(request)
   116  	assert.NoError(t, err)
   117  	assert.Equal(t, commands.FormatAccountAddressToResponse(accountAddress), response)
   118  
   119  	// Send transaction
   120  	request = fmt.Sprintf("{\"method\": \"eth_sendTransaction\", \"params\":[{\"from\":\"%s\",\"to\":\"0x0200000000000000000000000000000000000000\",\"value\":\"0x12345\",\"data\":\"0x307830\"}], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }", accountAddress.Hex())
   121  	response, err = api.CallRPC(request)
   122  	assert.NoError(t, err)
   123  	assert.Equal(t, expectedHash.Hex(), response)
   124  
   125  	// Personal sign
   126  	request = "{\"method\": \"personal_sign\", \"params\":[{\"challenge\": \"0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e\",\"address\":\"0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7\"}], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
   127  	response, err = api.CallRPC(request)
   128  	assert.NoError(t, err)
   129  	assert.Equal(t, expectedSignature, response)
   130  
   131  	// Revoke permissions
   132  	request = "{\"method\": \"wallet_revokePermissions\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
   133  	_, err = api.CallRPC(request)
   134  	assert.NoError(t, err)
   135  
   136  	// Check if the account was revoked
   137  	request = fmt.Sprintf("{\"method\": \"eth_sendTransaction\", \"params\":[{\"from\":\"%s\",\"to\":\"0x0200000000000000000000000000000000000000\",\"value\":\"0x12345\",\"data\":\"0x307830\"}], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }", accountAddress.Hex())
   138  	response, err = api.CallRPC(request)
   139  	assert.Empty(t, response)
   140  	assert.Error(t, err)
   141  	assert.Equal(t, commands.ErrDAppIsNotPermittedByUser, err)
   142  	assert.Equal(t, true, dAppPermissionRevoked)
   143  }
   144  
   145  func TestForwardedRPCs(t *testing.T) {
   146  	db, close := createDB(t)
   147  	defer close()
   148  
   149  	rpc := commands.RPCClientMock{}
   150  	service := NewService(db, &rpc, nil)
   151  
   152  	api := NewAPI(service)
   153  
   154  	sharedAccount := types.BytesToAddress(types.FromHex("0x3d0ab2a774b74bb1d36f97700315adf962c69fct"))
   155  
   156  	testDAppData := signal.ConnectorDApp{
   157  		URL:     "https://app.test.org",
   158  		Name:    "testDAppName",
   159  		IconURL: "https://app.test.icon.org",
   160  	}
   161  
   162  	request := "{\"method\": \"eth_blockNumber\", \"params\":[],\"url\":\"https://app.test.org\",\"name\":\"testDAppName\",\"iconUrl\":\"http://testDAppIconUrl\"}"
   163  	_, err := api.CallRPC(request)
   164  	assert.Equal(t, commands.ErrDAppIsNotPermittedByUser, err)
   165  
   166  	err = commands.PersistDAppData(db, testDAppData, sharedAccount, 0x123)
   167  	assert.NoError(t, err)
   168  
   169  	expectedResponse := "0xaa37dc"
   170  	rpc.SetResponse(fmt.Sprintf(`{"jsonrpc":"2.0","id":37,"result":"%s"}`, expectedResponse))
   171  
   172  	response, err := api.CallRPC(request)
   173  	assert.NoError(t, err)
   174  	assert.Equal(t, expectedResponse, response)
   175  }
   176  
   177  func TestRequestAccountsAfterPermisasionsRevokeTest(t *testing.T) {
   178  	db, close := createDB(t)
   179  	defer close()
   180  
   181  	nm := commands.NetworkManagerMock{}
   182  	nm.SetNetworks([]*params.Network{
   183  		{
   184  			ChainID: walletCommon.EthereumMainnet,
   185  			Layer:   1,
   186  		},
   187  		{
   188  			ChainID: walletCommon.OptimismMainnet,
   189  			Layer:   1,
   190  		},
   191  	})
   192  	rpc := commands.RPCClientMock{}
   193  
   194  	service := NewService(db, &rpc, &nm)
   195  
   196  	api := NewAPI(service)
   197  
   198  	accountAddress := types.BytesToAddress(types.FromHex("0x6d0aa2a774b74bb1d36f97700315adf962c69fcg"))
   199  	dAppPermissionRevoked := false
   200  	dAppPermissionGranted := false
   201  
   202  	signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
   203  		var evt commands.EventType
   204  		err := json.Unmarshal(s, &evt)
   205  		assert.NoError(t, err)
   206  
   207  		switch evt.Type {
   208  		case signal.EventConnectorDAppPermissionRevoked:
   209  			dAppPermissionRevoked = true
   210  		case signal.EventConnectorDAppPermissionGranted:
   211  			dAppPermissionGranted = true
   212  		case signal.EventConnectorSendRequestAccounts:
   213  			var ev signal.ConnectorSendRequestAccountsSignal
   214  			err := json.Unmarshal(evt.Event, &ev)
   215  			assert.NoError(t, err)
   216  
   217  			err = api.RequestAccountsAccepted(commands.RequestAccountsAcceptedArgs{
   218  				RequestID: ev.RequestID,
   219  				Account:   accountAddress,
   220  				ChainID:   0x1,
   221  			})
   222  			assert.NoError(t, err)
   223  		}
   224  	}))
   225  	t.Cleanup(signal.ResetMobileSignalHandler)
   226  
   227  	for range [10]int{} {
   228  		dAppPermissionRevoked = false
   229  		dAppPermissionGranted = false
   230  
   231  		// Request accounts
   232  		request := "{\"method\": \"eth_requestAccounts\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
   233  		response, err := api.CallRPC(request)
   234  		assert.NoError(t, err)
   235  		assert.Equal(t, commands.FormatAccountAddressToResponse(accountAddress), response)
   236  		assert.Equal(t, true, dAppPermissionGranted)
   237  		assert.Equal(t, false, dAppPermissionRevoked)
   238  
   239  		// Revoke permissions
   240  		request = "{\"method\": \"wallet_revokePermissions\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
   241  		_, err = api.CallRPC(request)
   242  		assert.NoError(t, err)
   243  		assert.Equal(t, true, dAppPermissionRevoked)
   244  	}
   245  }