Skip to content

Commit

Permalink
test_: added transaction from route test
Browse files Browse the repository at this point in the history
  • Loading branch information
antdanchenko authored and saledjenic committed Oct 1, 2024
1 parent 5ad830c commit 4773c62
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 35 deletions.
15 changes: 12 additions & 3 deletions integration-tests/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,17 @@
},
"Networks": [
{
"ChainID": 31337,
"RPCURL": "http://anvil:8545"
}
"ChainID": 31337,
"ChainName": "Anvil",
"DefaultRPCURL": "http://anvil:8545",
"RPCURL": "http://anvil:8545",
"ShortName": "eth",
"NativeCurrencyName": "Ether",
"NativeCurrencySymbol": "ETH",
"NativeCurrencyDecimals": 18,
"IsTest": false,
"Layer": 1,
"Enabled": true
}
]
}
10 changes: 8 additions & 2 deletions integration-tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ def pytest_addoption(parser):
help="",
default="ws://0.0.0.0:8354",
)
parser.addoption(
"--anvil_url",
action="store",
help="",
default="http://0.0.0.0:8545",
)
parser.addoption(
"--password",
action="store",
Expand All @@ -35,11 +41,11 @@ class Account():
private_key: str

user_1 = Account(
address="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
address="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
)
user_2 = Account(
address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
address="0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
)

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/docker-compose.anvil.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ services:
image: ghcr.io/foundry-rs/foundry:latest
platform: linux/amd64
command:
- anvil --host 0.0.0.0
- anvil --host 0.0.0.0 --block-time 2

deploy-sntv2:
platform: linux/amd64
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/docker-compose.test.status-go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ services:
"--password", "Strong12345",
"--dir", "/tmp/status-go-data", # Keep in sync with `config.json/DataDir` value. Later this arg will not be needed.
]
ports:
- 3333:3333
# - 8354:8354 # use for local debbuging only
healthcheck:
test: ["CMD-SHELL", "curl -X POST --data '{\"jsonrpc\":\"2.0\",\"method\":\"net_version\",\"params\":[],\"id\":1}' -H 'Content-Type: application/json' http://0.0.0.0:3333 || exit 1"]
interval: 5s
Expand Down Expand Up @@ -72,6 +75,8 @@ services:
"-m", "wallet",
"--rpc_url=http://status-go:3333",
"--rpc_url_2=http://status-go-no-funds:3333",
"--anvil_url=http://anvil:8545",
"--ws_url=ws://status-go:8354",
"--junitxml=/tests-rpc/reports/report.xml",
]
volumes:
Expand Down
54 changes: 34 additions & 20 deletions integration-tests/tests/test_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import threading
import logging
import jsonschema
import time
import requests
from conftest import option, user_1, user_2

Expand All @@ -16,9 +17,11 @@ def _try_except_JSONDecodeError_KeyError(self, response, key: str):
try:
return response.json()[key]
except json.JSONDecodeError:
raise AssertionError(f"Invalid JSON in response: {response.content}")
raise AssertionError(
f"Invalid JSON in response: {response.content}")
except KeyError:
raise AssertionError(f"Key '{key}' not found in the JSON response.")
raise AssertionError(
f"Key '{key}' not found in the JSON response: {response.content}")

def verify_is_valid_json_rpc_response(self, response, _id=None):
assert response.status_code == 200
Expand All @@ -40,7 +43,6 @@ def verify_is_json_rpc_error(self, response):
assert response.content
self._try_except_JSONDecodeError_KeyError(response, "error")


def rpc_request(self, method, params=[], _id=None, client=None, url=None):
client = client if client else requests.Session()
url = url if url else option.rpc_url
Expand All @@ -60,28 +62,27 @@ def verify_json_schema(self, response, method):
schema=json.load(schema))



class TransactionTestCase(RpcTestCase):


def wallet_create_multi_transaction(self, **kwargs):
method = "wallet_createMultiTransaction"
transferTx_data = {
"data": "",
"from": user_1.address,
"gas": "0x5BBF",
"input": "",
"maxFeePerGas": "0xbcc0f04fd",
"maxPriorityFeePerGas": "0xbcc0f04fd",
"to": user_2.address,
"type": "0x02",
"value": "0x5af3107a4000",
}
"data": "",
"from": user_1.address,
"gas": "0x5BBF",
"input": "",
"maxFeePerGas": "0xbcc0f04fd",
"maxPriorityFeePerGas": "0xbcc0f04fd",
"to": user_2.address,
"type": "0x02",
"value": "0x5af3107a4000",
}
for key, new_value in kwargs.items():
if key in transferTx_data:
transferTx_data[key] = new_value
else:
print(f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.")
print(
f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.")
params = [
{
"fromAddress": user_1.address,
Expand Down Expand Up @@ -116,10 +117,23 @@ def setup_method(self):

class SignalTestCase(RpcTestCase):

received_signals = []
await_signals = []
received_signals = {}

def on_message(self, ws, signal):
signal = json.loads(signal)
if signal.get("type") in self.await_signals:
self.received_signals[signal["type"]] = signal

def _on_message(self, ws, signal):
self.received_signals.append(signal)
def wait_for_signal(self, signal_type, timeout=10):
start_time = time.time()
while signal_type not in self.received_signals:
time_passed = time.time() - start_time
if time_passed >= timeout:
raise TimeoutError(
f"Signal {signal_type} is not received in {timeout} seconds")
time.sleep(0.5)
return self.received_signals[signal_type]

def _on_error(self, ws, error):
logging.info(f"Error: {error}")
Expand All @@ -134,7 +148,7 @@ def _connect(self):
self.url = f"{option.ws_url}/signals"

ws = websocket.WebSocketApp(self.url,
on_message=self._on_message,
on_message=self.on_message,
on_error=self._on_error,
on_close=self._on_close)

Expand Down
120 changes: 120 additions & 0 deletions integration-tests/tests/test_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import pytest
import time
import uuid
from conftest import user_1, user_2, option
from test_cases import SignalTestCase


@pytest.mark.rpc
@pytest.mark.transaction
@pytest.mark.wallet
class TestTransactionFromRoute(SignalTestCase):

await_signals = [
"wallet.suggested.routes",
"wallet.router.sign-transactions",
"wallet.router.sending-transactions-started",
"wallet.transaction.status-changed",
"wallet.router.transactions-sent"
]

def test_tx_from_route(self):

_uuid = str(uuid.uuid4())
amount_in = "0xde0b6b3a7640000"

method = "wallet_getSuggestedRoutesAsync"
params = [
{
"uuid": _uuid,
"sendType": 0,
"addrFrom": user_1.address,
"addrTo": user_2.address,
"amountIn": amount_in,
"amountOut": "0x0",
"tokenID": "ETH",
"tokenIDIsOwnerToken": False,
"toTokenID": "",
"disabledFromChainIDs": [10, 42161],
"disabledToChainIDs": [10, 42161],
"gasFeeMode": 1,
"fromLockedAmount": {}
}
]
response = self.rpc_request(method, params)
self.verify_is_valid_json_rpc_response(response)

routes = self.wait_for_signal("wallet.suggested.routes")
assert routes['event']['Uuid'] == _uuid

method = "wallet_buildTransactionsFromRoute"
params = [
{
"uuid": _uuid,
"slippagePercentage": 0
}
]
response = self.rpc_request(method, params)
self.verify_is_valid_json_rpc_response(response)

self.wait_for_signal("wallet.router.sign-transactions")

assert self.received_signals[
'wallet.router.sign-transactions']['event']['signingDetails']['signOnKeycard'] == False
transaction_hashes = self.received_signals[
'wallet.router.sign-transactions']['event']['signingDetails']['hashes']

assert transaction_hashes, "Transaction hashes are empty!"

tx_signatures = {}

for hash in transaction_hashes:

method = "wallet_signMessage"
params = [
hash,
user_1.address,
option.password
]

response = self.rpc_request(method, params)
self.verify_is_valid_json_rpc_response(response)

if response.json()["result"].startswith("0x"):
tx_signature = response.json()["result"][2:]

signature = {
"r": tx_signature[:64],
"s": tx_signature[64:128],
"v": tx_signature[128:]
}

tx_signatures[hash] = signature

method = "wallet_sendRouterTransactionsWithSignatures"
params = [
{
"uuid": _uuid,
"Signatures": tx_signatures
}
]
response = self.rpc_request(method, params)
self.verify_is_valid_json_rpc_response(response)

tx_status = self.wait_for_signal("wallet.transaction.status-changed")


assert tx_status["event"]["chainId"] == 31337
assert tx_status["event"]["status"] == "Success"
tx_hash = tx_status["event"]["hash"]

method = "eth_getTransactionByHash"
params = [tx_hash]

response = self.rpc_request(method, params, url=option.anvil_url)
self.verify_is_valid_json_rpc_response(response)
tx_details = response.json()["result"]

assert tx_details["value"] == amount_in
assert tx_details["to"] == user_2.address
assert tx_details["from"] == user_1.address
3 changes: 1 addition & 2 deletions integration-tests/tests/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ class TestRpc(RpcTestCase):
("wallet_getEthereumChains", []),
("wallet_getTokenList", []),
("wallet_getCryptoOnRamps", []),
("wallet_getCachedCurrencyFormats", []),
("wallet_fetchAllCurrencyFormats", [])
("wallet_getCachedCurrencyFormats", [])
],
)
def test_(self, method, params):
Expand Down
1 change: 1 addition & 0 deletions services/wallet/common/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
ArbitrumSepolia uint64 = 421614
BinanceChainID uint64 = 56 // obsolete?
BinanceTestChainID uint64 = 97 // obsolete?
AnvilMainnet uint64 = 31337
)

var (
Expand Down
22 changes: 15 additions & 7 deletions services/wallet/router/router_updates.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import (
)

var (
newBlockCheckIntervalMainnet = 3 * time.Second
newBlockCheckIntervalOptimism = 1 * time.Second
newBlockCheckIntervalArbitrum = 200 * time.Millisecond
newBlockCheckIntervalMainnet = 3 * time.Second
newBlockCheckIntervalOptimism = 1 * time.Second
newBlockCheckIntervalArbitrum = 200 * time.Millisecond
newBlockCheckIntervalAnvilMainnet = 2 * time.Second

feeRecalculationTimeout = 5 * time.Minute
feeRecalculationTimeout = 5 * time.Minute
feeRecalculationAnvilTimeout = 5 * time.Second
)

type fetchingLastBlock struct {
Expand All @@ -42,7 +44,11 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
}
r.clientsForUpdatesPerChains.Store(chainID, flb)

r.startTimeoutForUpdates(flb.closeCh)
timeout := feeRecalculationTimeout
if chainID == walletCommon.AnvilMainnet {
timeout = feeRecalculationAnvilTimeout
}
r.startTimeoutForUpdates(flb.closeCh, timeout)

var ticker *time.Ticker
switch chainID {
Expand All @@ -55,6 +61,8 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
case walletCommon.ArbitrumMainnet,
walletCommon.ArbitrumSepolia:
ticker = time.NewTicker(newBlockCheckIntervalArbitrum)
case walletCommon.AnvilMainnet:
ticker = time.NewTicker(newBlockCheckIntervalAnvilMainnet)
}

ctx, cancelCtx := context.WithCancel(context.Background())
Expand Down Expand Up @@ -123,8 +131,8 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
return nil
}

func (r *Router) startTimeoutForUpdates(closeCh chan struct{}) {
dedlineTicker := time.NewTicker(feeRecalculationTimeout)
func (r *Router) startTimeoutForUpdates(closeCh chan struct{}, timeout time.Duration) {
dedlineTicker := time.NewTicker(timeout)
go func() {
defer gocommon.LogOnPanic()
for {
Expand Down

0 comments on commit 4773c62

Please sign in to comment.