test_: added transaction from route test

This commit is contained in:
Anton 2024-09-25 14:27:04 +02:00 committed by Anthony Laibe
parent 28506bcd17
commit 107e2cb8da
9 changed files with 197 additions and 35 deletions

View File

@ -18,7 +18,16 @@
"Networks": [ "Networks": [
{ {
"ChainID": 31337, "ChainID": 31337,
"RPCURL": "http://anvil:8545" "ChainName": "Anvil",
"DefaultRPCURL": "http://anvil:8545",
"RPCURL": "http://anvil:8545",
"ShortName": "eth",
"NativeCurrencyName": "Ether",
"NativeCurrencySymbol": "ETH",
"NativeCurrencyDecimals": 18,
"IsTest": false,
"Layer": 1,
"Enabled": true
} }
] ]
} }

View File

@ -21,6 +21,12 @@ def pytest_addoption(parser):
help="", help="",
default="ws://0.0.0.0:8354", default="ws://0.0.0.0:8354",
) )
parser.addoption(
"--anvil_url",
action="store",
help="",
default="http://0.0.0.0:8545",
)
parser.addoption( parser.addoption(
"--password", "--password",
action="store", action="store",
@ -35,11 +41,11 @@ class Account():
private_key: str private_key: str
user_1 = Account( user_1 = Account(
address="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", address="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
) )
user_2 = Account( user_2 = Account(
address="0x70997970C51812dc3A010C7d01b50e0d17dc79C8", address="0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
) )

View File

@ -3,7 +3,7 @@ services:
image: ghcr.io/foundry-rs/foundry:latest image: ghcr.io/foundry-rs/foundry:latest
platform: linux/amd64 platform: linux/amd64
command: command:
- anvil --host 0.0.0.0 - anvil --host 0.0.0.0 --block-time 2
deploy-sntv2: deploy-sntv2:
platform: linux/amd64 platform: linux/amd64

View File

@ -16,6 +16,9 @@ services:
"--password", "Strong12345", "--password", "Strong12345",
"--dir", "/tmp/status-go-data", # Keep in sync with `config.json/DataDir` value. Later this arg will not be needed. "--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: 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"] 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 interval: 5s
@ -72,6 +75,8 @@ services:
"-m", "wallet", "-m", "wallet",
"--rpc_url=http://status-go:3333", "--rpc_url=http://status-go:3333",
"--rpc_url_2=http://status-go-no-funds: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", "--junitxml=/tests-rpc/reports/report.xml",
] ]
volumes: volumes:

View File

@ -3,6 +3,7 @@ import websocket
import threading import threading
import logging import logging
import jsonschema import jsonschema
import time
import requests import requests
from conftest import option, user_1, user_2 from conftest import option, user_1, user_2
@ -16,9 +17,11 @@ class RpcTestCase:
try: try:
return response.json()[key] return response.json()[key]
except json.JSONDecodeError: except json.JSONDecodeError:
raise AssertionError(f"Invalid JSON in response: {response.content}") raise AssertionError(
f"Invalid JSON in response: {response.content}")
except KeyError: 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): def verify_is_valid_json_rpc_response(self, response, _id=None):
assert response.status_code == 200 assert response.status_code == 200
@ -40,7 +43,6 @@ class RpcTestCase:
assert response.content assert response.content
self._try_except_JSONDecodeError_KeyError(response, "error") self._try_except_JSONDecodeError_KeyError(response, "error")
def rpc_request(self, method, params=[], _id=None, client=None, url=None): def rpc_request(self, method, params=[], _id=None, client=None, url=None):
client = client if client else requests.Session() client = client if client else requests.Session()
url = url if url else option.rpc_url url = url if url else option.rpc_url
@ -60,10 +62,8 @@ class RpcTestCase:
schema=json.load(schema)) schema=json.load(schema))
class TransactionTestCase(RpcTestCase): class TransactionTestCase(RpcTestCase):
def wallet_create_multi_transaction(self, **kwargs): def wallet_create_multi_transaction(self, **kwargs):
method = "wallet_createMultiTransaction" method = "wallet_createMultiTransaction"
transferTx_data = { transferTx_data = {
@ -81,7 +81,8 @@ class TransactionTestCase(RpcTestCase):
if key in transferTx_data: if key in transferTx_data:
transferTx_data[key] = new_value transferTx_data[key] = new_value
else: 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 = [ params = [
{ {
"fromAddress": user_1.address, "fromAddress": user_1.address,
@ -116,10 +117,23 @@ class TransactionTestCase(RpcTestCase):
class SignalTestCase(RpcTestCase): class SignalTestCase(RpcTestCase):
received_signals = [] await_signals = []
received_signals = {}
def _on_message(self, ws, signal): def on_message(self, ws, signal):
self.received_signals.append(signal) signal = json.loads(signal)
if signal.get("type") in self.await_signals:
self.received_signals[signal["type"]] = 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): def _on_error(self, ws, error):
logging.info(f"Error: {error}") logging.info(f"Error: {error}")
@ -134,7 +148,7 @@ class SignalTestCase(RpcTestCase):
self.url = f"{option.ws_url}/signals" self.url = f"{option.ws_url}/signals"
ws = websocket.WebSocketApp(self.url, ws = websocket.WebSocketApp(self.url,
on_message=self._on_message, on_message=self.on_message,
on_error=self._on_error, on_error=self._on_error,
on_close=self._on_close) on_close=self._on_close)

View File

@ -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

View File

@ -84,8 +84,7 @@ class TestRpc(RpcTestCase):
("wallet_getEthereumChains", []), ("wallet_getEthereumChains", []),
("wallet_getTokenList", []), ("wallet_getTokenList", []),
("wallet_getCryptoOnRamps", []), ("wallet_getCryptoOnRamps", []),
("wallet_getCachedCurrencyFormats", []), ("wallet_getCachedCurrencyFormats", [])
("wallet_fetchAllCurrencyFormats", [])
], ],
) )
def test_(self, method, params): def test_(self, method, params):

View File

@ -30,6 +30,7 @@ const (
ArbitrumSepolia uint64 = 421614 ArbitrumSepolia uint64 = 421614
BinanceChainID uint64 = 56 // obsolete? BinanceChainID uint64 = 56 // obsolete?
BinanceTestChainID uint64 = 97 // obsolete? BinanceTestChainID uint64 = 97 // obsolete?
AnvilMainnet uint64 = 31337
) )
var ( var (

View File

@ -14,8 +14,10 @@ var (
newBlockCheckIntervalMainnet = 3 * time.Second newBlockCheckIntervalMainnet = 3 * time.Second
newBlockCheckIntervalOptimism = 1 * time.Second newBlockCheckIntervalOptimism = 1 * time.Second
newBlockCheckIntervalArbitrum = 200 * time.Millisecond newBlockCheckIntervalArbitrum = 200 * time.Millisecond
newBlockCheckIntervalAnvilMainnet = 2 * time.Second
feeRecalculationTimeout = 5 * time.Minute feeRecalculationTimeout = 5 * time.Minute
feeRecalculationAnvilTimeout = 5 * time.Second
) )
type fetchingLastBlock struct { type fetchingLastBlock struct {
@ -42,7 +44,11 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
} }
r.clientsForUpdatesPerChains.Store(chainID, flb) 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 var ticker *time.Ticker
switch chainID { switch chainID {
@ -55,6 +61,8 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
case walletCommon.ArbitrumMainnet, case walletCommon.ArbitrumMainnet,
walletCommon.ArbitrumSepolia: walletCommon.ArbitrumSepolia:
ticker = time.NewTicker(newBlockCheckIntervalArbitrum) ticker = time.NewTicker(newBlockCheckIntervalArbitrum)
case walletCommon.AnvilMainnet:
ticker = time.NewTicker(newBlockCheckIntervalAnvilMainnet)
} }
ctx, cancelCtx := context.WithCancel(context.Background()) ctx, cancelCtx := context.WithCancel(context.Background())
@ -123,8 +131,8 @@ func (r *Router) subscribeForUdates(chainID uint64) error {
return nil return nil
} }
func (r *Router) startTimeoutForUpdates(closeCh chan struct{}) { func (r *Router) startTimeoutForUpdates(closeCh chan struct{}, timeout time.Duration) {
dedlineTicker := time.NewTicker(feeRecalculationTimeout) dedlineTicker := time.NewTicker(timeout)
go func() { go func() {
defer gocommon.LogOnPanic() defer gocommon.LogOnPanic()
for { for {