2024-07-18 15:30:10 +00:00
|
|
|
package connector
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2024-09-19 18:24:28 +00:00
|
|
|
"errors"
|
2024-07-18 15:30:10 +00:00
|
|
|
"fmt"
|
2024-09-19 18:24:28 +00:00
|
|
|
"math/big"
|
2024-07-18 15:30:10 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2024-07-18 15:30:10 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2024-09-19 18:24:28 +00:00
|
|
|
mock_client "github.com/status-im/status-go/rpc/chain/mock/client"
|
2024-08-02 07:43:31 +00:00
|
|
|
"github.com/status-im/status-go/services/connector/chainutils"
|
2024-07-18 15:30:10 +00:00
|
|
|
"github.com/status-im/status-go/services/connector/commands"
|
2024-08-02 07:43:31 +00:00
|
|
|
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
2024-07-18 15:30:10 +00:00
|
|
|
"github.com/status-im/status-go/signal"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestRequestAccountsSwitchChainAndSendTransactionFlow(t *testing.T) {
|
2024-09-19 18:24:28 +00:00
|
|
|
state, closeFn := setupTests(t)
|
|
|
|
t.Cleanup(closeFn)
|
2024-07-18 15:30:10 +00:00
|
|
|
|
|
|
|
accountAddress := types.BytesToAddress(types.FromHex("0x6d0aa2a774b74bb1d36f97700315adf962c69fcg"))
|
|
|
|
expectedHash := types.BytesToHash(types.FromHex("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"))
|
2024-08-13 09:11:24 +00:00
|
|
|
expectedSignature := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
|
2024-07-18 15:30:10 +00:00
|
|
|
|
2024-08-06 19:28:55 +00:00
|
|
|
dAppPermissionRevoked := false
|
|
|
|
dAppPermissionGranted := false
|
|
|
|
|
2024-07-18 15:30:10 +00:00
|
|
|
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
|
|
|
|
var evt commands.EventType
|
|
|
|
err := json.Unmarshal(s, &evt)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
switch evt.Type {
|
2024-08-06 19:28:55 +00:00
|
|
|
case signal.EventConnectorDAppPermissionRevoked:
|
|
|
|
dAppPermissionRevoked = true
|
|
|
|
case signal.EventConnectorDAppPermissionGranted:
|
|
|
|
dAppPermissionGranted = true
|
2024-07-18 15:30:10 +00:00
|
|
|
case signal.EventConnectorSendRequestAccounts:
|
|
|
|
var ev signal.ConnectorSendRequestAccountsSignal
|
|
|
|
err := json.Unmarshal(evt.Event, &ev)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
err = state.api.RequestAccountsAccepted(commands.RequestAccountsAcceptedArgs{
|
2024-07-18 15:30:10 +00:00
|
|
|
RequestID: ev.RequestID,
|
|
|
|
Account: accountAddress,
|
|
|
|
ChainID: 0x1,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
case signal.EventConnectorSendTransaction:
|
|
|
|
var ev signal.ConnectorSendTransactionSignal
|
|
|
|
err := json.Unmarshal(evt.Event, &ev)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
err = state.api.SendTransactionAccepted(commands.SendTransactionAcceptedArgs{
|
2024-07-18 15:30:10 +00:00
|
|
|
RequestID: ev.RequestID,
|
|
|
|
Hash: expectedHash,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-08-13 09:11:24 +00:00
|
|
|
case signal.EventConnectorPersonalSign:
|
|
|
|
var ev signal.ConnectorPersonalSignSignal
|
|
|
|
err := json.Unmarshal(evt.Event, &ev)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
err = state.api.PersonalSignAccepted(commands.PersonalSignAcceptedArgs{
|
2024-08-13 09:11:24 +00:00
|
|
|
RequestID: ev.RequestID,
|
|
|
|
Signature: expectedSignature,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-07-18 15:30:10 +00:00
|
|
|
}
|
|
|
|
}))
|
2024-09-03 08:41:56 +00:00
|
|
|
t.Cleanup(signal.ResetMobileSignalHandler)
|
2024-07-18 15:30:10 +00:00
|
|
|
|
|
|
|
// Request accounts, now for real
|
2024-08-06 19:28:55 +00:00
|
|
|
request := "{\"method\": \"eth_requestAccounts\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err := state.api.CallRPC(state.ctx, request)
|
2024-07-18 15:30:10 +00:00
|
|
|
assert.NoError(t, err)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.Equal(t, commands.FormatAccountAddressToResponse(accountAddress), response)
|
2024-08-06 19:28:55 +00:00
|
|
|
assert.Equal(t, true, dAppPermissionGranted)
|
|
|
|
assert.Equal(t, false, dAppPermissionRevoked)
|
2024-07-18 15:30:10 +00:00
|
|
|
|
|
|
|
// Request to switch ethereum chain
|
2024-08-02 07:43:31 +00:00
|
|
|
expectedChainID, err := chainutils.GetHexChainID(walletCommon.ChainID(walletCommon.EthereumMainnet).String())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
request = fmt.Sprintf("{\"method\": \"wallet_switchEthereumChain\", \"params\": [{\"chainId\": \"%s\"}], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }", expectedChainID)
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-07-18 15:30:10 +00:00
|
|
|
assert.NoError(t, err)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.Equal(t, expectedChainID, response)
|
2024-07-18 15:30:10 +00:00
|
|
|
|
|
|
|
// Check if the chain was switched
|
|
|
|
request = "{\"method\": \"eth_chainId\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-07-18 15:30:10 +00:00
|
|
|
assert.NoError(t, err)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.Equal(t, expectedChainID, response)
|
2024-07-18 15:30:10 +00:00
|
|
|
|
|
|
|
// Check the account after switching chain
|
|
|
|
request = "{\"method\": \"eth_accounts\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-07-18 15:30:10 +00:00
|
|
|
assert.NoError(t, err)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.Equal(t, commands.FormatAccountAddressToResponse(accountAddress), response)
|
2024-07-18 15:30:10 +00:00
|
|
|
|
|
|
|
// Send transaction
|
2024-09-19 18:24:28 +00:00
|
|
|
mockedChainClient := mock_client.NewMockClientInterface(state.mockCtrl)
|
|
|
|
state.rpcClient.EXPECT().EthClient(uint64(1)).Times(1).Return(mockedChainClient, nil)
|
|
|
|
mockedChainClient.EXPECT().SuggestGasPrice(state.ctx).Times(1).Return(big.NewInt(1), nil)
|
|
|
|
mockedChainClient.EXPECT().SuggestGasTipCap(state.ctx).Times(1).Return(big.NewInt(0), errors.New("EIP-1559 is not enabled"))
|
|
|
|
state.rpcClient.EXPECT().EthClient(uint64(1)).Times(1).Return(mockedChainClient, nil)
|
|
|
|
mockedChainClient.EXPECT().PendingNonceAt(state.ctx, common.Address(accountAddress)).Times(1).Return(uint64(10), nil)
|
|
|
|
|
2024-07-18 15:30:10 +00:00
|
|
|
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())
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-07-18 15:30:10 +00:00
|
|
|
assert.NoError(t, err)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.Equal(t, expectedHash.Hex(), response)
|
2024-08-06 19:28:55 +00:00
|
|
|
|
2024-08-13 09:11:24 +00:00
|
|
|
// Personal sign
|
2024-11-11 14:09:01 +00:00
|
|
|
request = "{\"method\": \"personal_sign\", \"params\":[\"0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e\",\"0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7\"], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-08-13 09:11:24 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, expectedSignature, response)
|
|
|
|
|
2024-08-06 19:28:55 +00:00
|
|
|
// Revoke permissions
|
|
|
|
request = "{\"method\": \"wallet_revokePermissions\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-08-06 19:28:55 +00:00
|
|
|
assert.NoError(t, err)
|
2024-09-19 18:24:28 +00:00
|
|
|
assert.Empty(t, response)
|
2024-08-06 19:28:55 +00:00
|
|
|
|
|
|
|
// Check if the account was revoked
|
|
|
|
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())
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err = state.api.CallRPC(state.ctx, request)
|
2024-08-06 19:28:55 +00:00
|
|
|
assert.Empty(t, response)
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, commands.ErrDAppIsNotPermittedByUser, err)
|
|
|
|
assert.Equal(t, true, dAppPermissionRevoked)
|
2024-08-02 07:43:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestForwardedRPCs(t *testing.T) {
|
2024-09-19 18:24:28 +00:00
|
|
|
state, closeFn := setupTests(t)
|
|
|
|
t.Cleanup(closeFn)
|
2024-08-02 07:43:31 +00:00
|
|
|
|
|
|
|
sharedAccount := types.BytesToAddress(types.FromHex("0x3d0ab2a774b74bb1d36f97700315adf962c69fct"))
|
|
|
|
|
|
|
|
testDAppData := signal.ConnectorDApp{
|
|
|
|
URL: "https://app.test.org",
|
|
|
|
Name: "testDAppName",
|
|
|
|
IconURL: "https://app.test.icon.org",
|
|
|
|
}
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
requestJson := "{\"method\": \"eth_blockNumber\", \"params\":[],\"url\":\"https://app.test.org\",\"name\":\"testDAppName\",\"iconUrl\":\"http://testDAppIconUrl\"}"
|
|
|
|
request, err := commands.RPCRequestFromJSON(requestJson)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
request.ChainID = 291
|
|
|
|
byteRequest, err := json.Marshal(request)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expectedResponse := "0xaa37dc"
|
|
|
|
|
|
|
|
state.rpcClient.EXPECT().CallRaw(string(byteRequest)).Times(0)
|
|
|
|
|
|
|
|
_, err = state.api.CallRPC(state.ctx, requestJson)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.Equal(t, commands.ErrDAppIsNotPermittedByUser, err)
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
err = commands.PersistDAppData(state.walletDb, testDAppData, sharedAccount, 0x123)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
state.rpcClient.EXPECT().CallRaw(string(byteRequest)).Times(1).Return(fmt.Sprintf(`{"jsonrpc":"2.0","id":37,"result":"%s"}`, expectedResponse))
|
2024-08-02 07:43:31 +00:00
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err := state.api.CallRPC(state.ctx, requestJson)
|
2024-08-02 07:43:31 +00:00
|
|
|
assert.NoError(t, err)
|
2024-07-18 15:30:10 +00:00
|
|
|
assert.Equal(t, expectedResponse, response)
|
|
|
|
}
|
2024-08-15 11:49:29 +00:00
|
|
|
|
|
|
|
func TestRequestAccountsAfterPermisasionsRevokeTest(t *testing.T) {
|
2024-09-19 18:24:28 +00:00
|
|
|
state, closeFn := setupTests(t)
|
|
|
|
t.Cleanup(closeFn)
|
2024-08-15 11:49:29 +00:00
|
|
|
|
|
|
|
accountAddress := types.BytesToAddress(types.FromHex("0x6d0aa2a774b74bb1d36f97700315adf962c69fcg"))
|
|
|
|
dAppPermissionRevoked := false
|
|
|
|
dAppPermissionGranted := false
|
|
|
|
|
|
|
|
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
|
|
|
|
var evt commands.EventType
|
|
|
|
err := json.Unmarshal(s, &evt)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
switch evt.Type {
|
|
|
|
case signal.EventConnectorDAppPermissionRevoked:
|
|
|
|
dAppPermissionRevoked = true
|
|
|
|
case signal.EventConnectorDAppPermissionGranted:
|
|
|
|
dAppPermissionGranted = true
|
|
|
|
case signal.EventConnectorSendRequestAccounts:
|
|
|
|
var ev signal.ConnectorSendRequestAccountsSignal
|
|
|
|
err := json.Unmarshal(evt.Event, &ev)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-09-19 18:24:28 +00:00
|
|
|
err = state.api.RequestAccountsAccepted(commands.RequestAccountsAcceptedArgs{
|
2024-08-15 11:49:29 +00:00
|
|
|
RequestID: ev.RequestID,
|
|
|
|
Account: accountAddress,
|
|
|
|
ChainID: 0x1,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
}))
|
2024-09-03 08:41:56 +00:00
|
|
|
t.Cleanup(signal.ResetMobileSignalHandler)
|
2024-08-15 11:49:29 +00:00
|
|
|
|
|
|
|
for range [10]int{} {
|
|
|
|
dAppPermissionRevoked = false
|
|
|
|
dAppPermissionGranted = false
|
|
|
|
|
|
|
|
// Request accounts
|
|
|
|
request := "{\"method\": \"eth_requestAccounts\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
response, err := state.api.CallRPC(state.ctx, request)
|
2024-08-15 11:49:29 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, commands.FormatAccountAddressToResponse(accountAddress), response)
|
|
|
|
assert.Equal(t, true, dAppPermissionGranted)
|
|
|
|
assert.Equal(t, false, dAppPermissionRevoked)
|
|
|
|
|
|
|
|
// Revoke permissions
|
|
|
|
request = "{\"method\": \"wallet_revokePermissions\", \"params\": [], \"url\": \"http://testDAppURL123\", \"name\": \"testDAppName\", \"iconUrl\": \"http://testDAppIconUrl\" }"
|
2024-09-19 18:24:28 +00:00
|
|
|
_, err = state.api.CallRPC(state.ctx, request)
|
2024-08-15 11:49:29 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, true, dAppPermissionRevoked)
|
|
|
|
}
|
|
|
|
}
|