test_: added transaction from route test
This commit is contained in:
parent
28506bcd17
commit
107e2cb8da
|
@ -17,8 +17,17 @@
|
||||||
},
|
},
|
||||||
"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
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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,28 +62,27 @@ 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 = {
|
||||||
"data": "",
|
"data": "",
|
||||||
"from": user_1.address,
|
"from": user_1.address,
|
||||||
"gas": "0x5BBF",
|
"gas": "0x5BBF",
|
||||||
"input": "",
|
"input": "",
|
||||||
"maxFeePerGas": "0xbcc0f04fd",
|
"maxFeePerGas": "0xbcc0f04fd",
|
||||||
"maxPriorityFeePerGas": "0xbcc0f04fd",
|
"maxPriorityFeePerGas": "0xbcc0f04fd",
|
||||||
"to": user_2.address,
|
"to": user_2.address,
|
||||||
"type": "0x02",
|
"type": "0x02",
|
||||||
"value": "0x5af3107a4000",
|
"value": "0x5af3107a4000",
|
||||||
}
|
}
|
||||||
for key, new_value in kwargs.items():
|
for key, new_value in kwargs.items():
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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):
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -11,11 +11,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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 {
|
||||||
|
|
Loading…
Reference in New Issue