Skip to content

Commit 44bb434

Browse files
authored
feat: make send() gas stipend configurable (#3158)
make gas stipend configurable so that users can `send()` to contracts instead of resorting to `raw_call()`
1 parent e60b021 commit 44bb434

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

tests/parser/functions/test_send.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,37 @@ def __default__():
5656
assert receiver.last_sender() == sender.address
5757
assert w3.eth.get_balance(sender.address) == 0
5858
assert w3.eth.get_balance(receiver.address) == 1
59+
60+
61+
def test_send_gas_stipend(get_contract, w3):
62+
"""
63+
Tests to verify that adding gas stipend to send() will send sufficient gas
64+
"""
65+
66+
sender_code = """
67+
68+
@external
69+
def test_send_stipend(receiver: address):
70+
send(receiver, 1, gas=50000)
71+
"""
72+
73+
# default function writes variable, this requires more gas than
74+
# send would pass without gas stipend
75+
receiver_code = """
76+
last_sender: public(address)
77+
78+
@external
79+
@payable
80+
def __default__():
81+
self.last_sender = msg.sender
82+
"""
83+
84+
sender = get_contract(sender_code, value=1)
85+
receiver = get_contract(receiver_code)
86+
87+
sender.test_send_stipend(receiver.address, transact={"gas": 100000})
88+
89+
# value transfer hapenned, variable was changed
90+
assert receiver.last_sender() == sender.address
91+
assert w3.eth.get_balance(sender.address) == 0
92+
assert w3.eth.get_balance(receiver.address) == 1

tests/parser/syntax/test_send.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,44 @@ def foo():
5858
""",
5959
TypeMismatch,
6060
),
61+
# Tests for sending gas stipend
62+
(
63+
"""
64+
@external
65+
def foo():
66+
send(0x1234567890123456789012345678901234567890, 5, gas=1.5)
67+
""",
68+
InvalidType,
69+
),
70+
(
71+
"""
72+
@external
73+
def foo():
74+
send(0x1234567890123456789012345678901234567890, 5, gas=-2)
75+
""",
76+
InvalidType,
77+
),
78+
(
79+
"""
80+
x: int128
81+
82+
@external
83+
def foo():
84+
send(0x1234567890123456789012345678901234567890, 5, gas=self.x)
85+
""",
86+
TypeMismatch,
87+
),
88+
(
89+
"""
90+
x: decimal
91+
92+
@external
93+
def foo():
94+
send(0x1234567890123456789012345678901234567890, 5, gas=self.x)
95+
""",
96+
TypeMismatch,
97+
),
98+
# End tests for sending gas stipend
6199
]
62100

63101

@@ -109,6 +147,20 @@ def send(a: address, w: uint256):
109147
def foo():
110148
self.send(msg.sender, msg.value)
111149
""",
150+
"""
151+
#Test send gas stipend
152+
@external
153+
def foo():
154+
send(0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe, 5, gas=5000)
155+
""",
156+
"""
157+
x: uint256
158+
159+
#Test send gas stipend
160+
@external
161+
def foo():
162+
send(0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe, 5, gas=self.x)
163+
""",
112164
]
113165

114166

vyper/builtins/functions.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1246,13 +1246,16 @@ class Send(BuiltinFunction):
12461246

12471247
_id = "send"
12481248
_inputs = [("to", AddressT()), ("value", UINT256_T)]
1249+
# default gas stipend is 0
1250+
_kwargs = {"gas": KwargSettings(UINT256_T, 0)}
12491251
_return_type = None
12501252

12511253
@process_inputs
12521254
def build_IR(self, expr, args, kwargs, context):
12531255
to, value = args
1256+
gas = kwargs["gas"]
12541257
context.check_is_not_constant("send ether", expr)
1255-
return IRnode.from_list(["assert", ["call", 0, to, value, 0, 0, 0, 0]])
1258+
return IRnode.from_list(["assert", ["call", gas, to, value, 0, 0, 0, 0]])
12561259

12571260

12581261
class SelfDestruct(BuiltinFunction):

0 commit comments

Comments
 (0)