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 }