Skip to content

Commit edcbe9a

Browse files
tests
1 parent 3296ddf commit edcbe9a

File tree

3 files changed

+170
-11
lines changed

3 files changed

+170
-11
lines changed

cdp/smart_wallet.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ def send_user_operation(
9797
"""
9898
network = Network.from_chain_id(chain_id)
9999

100+
if not calls:
101+
raise ValueError("Calls list cannot be empty")
102+
100103
encoded_calls = []
101104
for call in calls:
102105
if isinstance(call, EVMAbiCallDict):

tests/factories/user_operation_factory.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ def _create_user_operation_model(
1919
status="pending",
2020
):
2121
if calls is None:
22-
calls = [Call(
23-
to="0x1234567890123456789012345678901234567890",
24-
value="1000000000000000000",
25-
data="0x",
22+
calls = [
23+
Call(
24+
to="0x1234567890123456789012345678901234567890",
25+
value="1000000000000000000",
26+
data="0x",
2627
)
2728
]
2829
return UserOperationModel(

tests/test_smart_wallet.py

Lines changed: 162 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from unittest.mock import Mock, patch
22

3+
import pytest
34
from eth_account import Account
45

56
from cdp.client.models.call import Call
67
from cdp.client.models.create_smart_wallet_request import CreateSmartWalletRequest
7-
from cdp.evm_call_types import EVMCallDict
8-
from cdp.smart_wallet import SmartWallet
8+
from cdp.evm_call_types import EVMAbiCallDict, EVMCallDict
9+
from cdp.smart_wallet import SmartWallet, to_smart_wallet
910
from cdp.user_operation import UserOperation
1011

1112

@@ -51,15 +52,14 @@ def test_smart_wallet_use_network(smart_wallet_factory):
5152

5253

5354
@patch("cdp.Cdp.api_clients")
54-
def test_smart_wallet_send_user_operation(
55+
def test_smart_wallet_send_user_operation_with_encoded_call(
5556
mock_api_clients, smart_wallet_factory, user_operation_model_factory, account_factory
5657
):
5758
"""Test SmartWallet send_user_operation method."""
5859
account = account_factory()
5960
smart_wallet_address = "0x1234567890123456789012345678901234567890"
6061
smart_wallet = smart_wallet_factory(smart_wallet_address, account)
6162

62-
# Create a mock user operation using UserOperationModel
6363
mock_user_operation = user_operation_model_factory(
6464
id="test-user-operation-id",
6565
network_id="base-sepolia",
@@ -70,7 +70,6 @@ def test_smart_wallet_send_user_operation(
7070
status="pending",
7171
)
7272

73-
# Setup the mock chain
7473
mock_create_user_operation = Mock(return_value=mock_user_operation)
7574
mock_api_clients.smart_wallets.create_user_operation = mock_create_user_operation
7675

@@ -80,14 +79,170 @@ def test_smart_wallet_send_user_operation(
8079
calls=calls, chain_id=84532, paymaster_url="https://paymaster.com"
8180
)
8281

83-
# Verify the mock was called with correct arguments
8482
mock_create_user_operation.assert_called_once()
8583

86-
# Verify the user operation properties match expected values
8784
assert user_operation.user_operation_id == mock_user_operation.id
8885
assert user_operation.smart_wallet_address == smart_wallet_address
8986
assert user_operation.unsigned_payload == mock_user_operation.unsigned_payload
9087
assert user_operation.signature == mock_user_operation.signature
9188
assert user_operation.transaction_hash == mock_user_operation.transaction_hash
9289
assert user_operation.status == UserOperation.Status(mock_user_operation.status)
9390
assert not user_operation.terminal_state
91+
92+
93+
@patch("cdp.Cdp.api_clients")
94+
def test_send_user_operation_with_abi_call(
95+
mock_api_clients, smart_wallet_factory, user_operation_model_factory, account_factory
96+
):
97+
"""Test sending user operation with EVMAbiCallDict."""
98+
account = account_factory()
99+
smart_wallet_address = "0x1234567890123456789012345678901234567890"
100+
smart_wallet = smart_wallet_factory(smart_wallet_address, account)
101+
102+
mock_user_operation = user_operation_model_factory(
103+
id="test-op-id",
104+
network_id="base-sepolia",
105+
calls=[Call(to=account.address, data="0x123", value="0")],
106+
unsigned_payload="0x" + "0" * 64,
107+
signature="0xe0a180fdd0fe38037cc878c03832861b40a29d32bd7b40b10c9e1efc8c1468a05ae06d1624896d0d29f4b31e32772ea3cb1b4d7ed4e077e5da28dcc33c0e78121c",
108+
transaction_hash="0x4567890123456789012345678901234567890123",
109+
status="pending",
110+
)
111+
112+
mock_create_user_operation = Mock(return_value=mock_user_operation)
113+
mock_api_clients.smart_wallets.create_user_operation = mock_create_user_operation
114+
115+
abi_call = EVMAbiCallDict(
116+
to=account.address,
117+
abi=[{"inputs": [], "name": "transfer", "type": "function"}],
118+
function_name="transfer",
119+
args=[],
120+
value=None,
121+
)
122+
123+
user_operation = smart_wallet.send_user_operation(calls=[abi_call], chain_id=84532)
124+
125+
assert user_operation.user_operation_id == mock_user_operation.id
126+
assert user_operation.smart_wallet_address == smart_wallet_address
127+
assert user_operation.unsigned_payload == mock_user_operation.unsigned_payload
128+
assert user_operation.signature == mock_user_operation.signature
129+
assert user_operation.transaction_hash == mock_user_operation.transaction_hash
130+
assert user_operation.status == UserOperation.Status(mock_user_operation.status)
131+
assert not user_operation.terminal_state
132+
mock_create_user_operation.assert_called_once()
133+
134+
135+
def test_smart_wallet_multiple_calls(smart_wallet_factory, account_factory):
136+
"""Test sending multiple calls in one operation."""
137+
account = account_factory()
138+
smart_wallet_address = "0x1234567890123456789012345678901234567890"
139+
smart_wallet = smart_wallet_factory(smart_wallet_address, account)
140+
141+
calls = [
142+
EVMCallDict(to=account.address, value=1000000000000000000, data="0x"),
143+
EVMCallDict(to=account.address, value=0, data="0x123"),
144+
EVMCallDict(to=account.address, value=None, data=None),
145+
]
146+
147+
with patch("cdp.Cdp.api_clients") as mock_api_clients:
148+
mock_user_operation = Mock(
149+
id="test-op-id",
150+
network_id="base-sepolia",
151+
calls=[Call(to=c.to, value=str(c.value or 0), data=c.data or "0x") for c in calls],
152+
unsigned_payload="0x" + "0" * 64,
153+
signature="0x" + "0" * 130,
154+
transaction_hash="0x" + "0" * 64,
155+
status="pending",
156+
)
157+
mock_api_clients.smart_wallets.create_user_operation.return_value = mock_user_operation
158+
159+
user_operation = smart_wallet.send_user_operation(calls=calls, chain_id=84532)
160+
assert user_operation.user_operation_id == "test-op-id"
161+
162+
163+
def test_network_scoped_wallet_initialization(smart_wallet_factory, account_factory):
164+
"""Test NetworkScopedSmartWallet initialization."""
165+
account = account_factory()
166+
smart_wallet_address = "0x1234567890123456789012345678901234567890"
167+
168+
network_wallet = smart_wallet_factory(smart_wallet_address, account).use_network(
169+
84532, "https://paymaster.com"
170+
)
171+
assert network_wallet.chain_id == 84532
172+
assert network_wallet.paymaster_url == "https://paymaster.com"
173+
174+
network_wallet = smart_wallet_factory(smart_wallet_address, account).use_network(84532)
175+
assert network_wallet.chain_id == 84532
176+
assert network_wallet.paymaster_url is None
177+
178+
179+
@patch("cdp.Cdp.api_clients")
180+
def test_network_scoped_wallet_send_operation(
181+
mock_api_clients, smart_wallet_factory, user_operation_model_factory, account_factory
182+
):
183+
"""Test NetworkScopedSmartWallet send_user_operation method."""
184+
account = account_factory()
185+
smart_wallet_address = "0x1234567890123456789012345678901234567890"
186+
network_wallet = smart_wallet_factory(smart_wallet_address, account).use_network(84532)
187+
188+
mock_user_operation = user_operation_model_factory(
189+
id="test-op-id",
190+
network_id="base-sepolia",
191+
calls=[Call(to=account.address, value="1000000000000000000", data="0x")],
192+
unsigned_payload="0x" + "0" * 64,
193+
signature="0xe0a180fdd0fe38037cc878c03832861b40a29d32bd7b40b10c9e1efc8c1468a05ae06d1624896d0d29f4b31e32772ea3cb1b4d7ed4e077e5da28dcc33c0e78121c",
194+
transaction_hash="0x4567890123456789012345678901234567890123",
195+
status="pending",
196+
)
197+
198+
mock_create_user_operation = Mock(return_value=mock_user_operation)
199+
mock_api_clients.smart_wallets.create_user_operation = mock_create_user_operation
200+
201+
calls = [EVMCallDict(to=account.address, value=1000000000000000000, data="0x")]
202+
user_operation = network_wallet.send_user_operation(calls=calls)
203+
204+
assert user_operation.user_operation_id == mock_user_operation.id
205+
assert user_operation.smart_wallet_address == smart_wallet_address
206+
assert user_operation.unsigned_payload == mock_user_operation.unsigned_payload
207+
assert user_operation.signature == mock_user_operation.signature
208+
assert user_operation.transaction_hash == mock_user_operation.transaction_hash
209+
assert user_operation.status == UserOperation.Status(mock_user_operation.status)
210+
assert not user_operation.terminal_state
211+
212+
213+
def test_network_scoped_wallet_string_representations(smart_wallet_factory, account_factory):
214+
"""Test NetworkScopedSmartWallet string representations."""
215+
account = account_factory()
216+
address = "0x1234567890123456789012345678901234567890"
217+
network_wallet = smart_wallet_factory(address, account).use_network(84532)
218+
219+
assert str(network_wallet) == f"Network Scoped Smart Wallet: {address} (Chain ID: 84532)"
220+
assert (
221+
repr(network_wallet)
222+
== f"Network Scoped Smart Wallet: (model=SmartWalletModel(address='{address}'), network=Network(chain_id=84532, paymaster_url=None))"
223+
)
224+
225+
226+
def test_to_smart_wallet_creation():
227+
"""Test to_smart_wallet function."""
228+
signer = Account.create()
229+
address = "0x1234567890123456789012345678901234567890"
230+
231+
wallet = to_smart_wallet(address, signer)
232+
assert wallet.address == address
233+
assert wallet.owners == [signer]
234+
235+
236+
@patch("cdp.Cdp.api_clients")
237+
def test_send_user_operation_with_empty_calls(
238+
mock_api_clients, smart_wallet_factory, account_factory
239+
):
240+
"""Test that sending empty calls list raises ValueError."""
241+
account = account_factory()
242+
smart_wallet_address = "0x1234567890123456789012345678901234567890"
243+
smart_wallet = smart_wallet_factory(smart_wallet_address, account)
244+
245+
with pytest.raises(ValueError, match="Calls list cannot be empty"):
246+
smart_wallet.send_user_operation(calls=[], chain_id=84532)
247+
248+
mock_api_clients.smart_wallets.create_user_operation.assert_not_called()

0 commit comments

Comments
 (0)