Skip to content

Commit 2d5e030

Browse files
author
Dev Kalra
authored
[executor] call contract with value (#1206)
* call contract with value * address feedback
1 parent 3e05edb commit 2d5e030

File tree

2 files changed

+129
-11
lines changed

2 files changed

+129
-11
lines changed

target_chains/ethereum/contracts/contracts/executor/Executor.sol

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ contract Executor {
2626
// This argument is included to support multiple Executors on the same blockchain.
2727
address executorAddress;
2828
address callAddress;
29+
// callAddress will be called with given value
30+
uint value;
2931
bytes callData;
3032
}
3133

@@ -87,7 +89,9 @@ contract Executor {
8789
if (len == 0) revert ExecutorErrors.InvalidContractTarget();
8890

8991
bool success;
90-
(success, response) = address(callAddress).call(gi.callData);
92+
(success, response) = address(callAddress).call{value: gi.value}(
93+
gi.callData
94+
);
9195

9296
// Check if the call was successful or not.
9397
if (!success) {
@@ -163,6 +167,9 @@ contract Executor {
163167
gi.callAddress = encodedInstruction.toAddress(index);
164168
index += 20;
165169

170+
gi.value = encodedInstruction.toUint256(index);
171+
index += 32;
172+
166173
// As solidity performs math operations in a checked mode
167174
// if the length of the encoded instruction be smaller than index
168175
// it will revert. So we don't need any extra check.

target_chains/ethereum/contracts/forge-test/Executor.t.sol

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ contract ExecutorTest is Test, WormholeTestUtils {
4141
function testExecute(
4242
address callAddress,
4343
bytes memory callData,
44-
uint64 sequence
44+
uint64 sequence,
45+
uint value
4546
) internal returns (bytes memory vaa) {
4647
bytes memory payload = abi.encodePacked(
4748
uint32(0x5054474d),
@@ -50,6 +51,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
5051
CHAIN_ID,
5152
address(executor),
5253
callAddress,
54+
value,
5355
callData
5456
);
5557

@@ -66,7 +68,8 @@ contract ExecutorTest is Test, WormholeTestUtils {
6668
}
6769

6870
function getTestUpgradeVaa(
69-
address newImplementation
71+
address newImplementation,
72+
uint value
7073
) internal returns (bytes memory vaa) {
7174
bytes memory payload = abi.encodePacked(
7275
uint32(0x5054474d),
@@ -75,6 +78,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
7578
CHAIN_ID,
7679
address(executor),
7780
address(executor),
81+
value,
7882
abi.encodeWithSelector(
7983
ExecutorUpgradable.upgradeTo.selector,
8084
newImplementation
@@ -101,19 +105,19 @@ contract ExecutorTest is Test, WormholeTestUtils {
101105
}
102106

103107
function testUpgradeCallSucceedsForContractWithCorrectMagic() public {
104-
bytes memory vaa = getTestUpgradeVaa(address(executor2));
108+
bytes memory vaa = getTestUpgradeVaa(address(executor2), 0);
105109
executor.execute(vaa);
106110
}
107111

108112
function testUpgradeCallFailsForNotUUPSContract() public {
109-
bytes memory vaa = getTestUpgradeVaa(address(callable));
113+
bytes memory vaa = getTestUpgradeVaa(address(callable), 0);
110114

111115
vm.expectRevert("ERC1967Upgrade: new implementation is not UUPS");
112116
executor.execute(vaa);
113117
}
114118

115119
function testUpgradeCallFailsForInvalidMagic() public {
116-
bytes memory vaa = getTestUpgradeVaa(address(executorInvalidMagic));
120+
bytes memory vaa = getTestUpgradeVaa(address(executorInvalidMagic), 0);
117121

118122
vm.expectRevert(ExecutorErrors.InvalidMagicValue.selector);
119123
executor.execute(vaa);
@@ -127,14 +131,70 @@ contract ExecutorTest is Test, WormholeTestUtils {
127131
testExecute(
128132
address(callable),
129133
abi.encodeWithSelector(ICallable.foo.selector),
130-
1
134+
1,
135+
0
131136
);
132137
assertEq(callable.fooCount(), c + 1);
133138
assertEq(callable.lastCaller(), address(executor));
134139
// Sanity check to make sure the check above is meaningful.
135140
assert(address(executor) != address(this));
136141
}
137142

143+
function testCallWithValueSucceeds() public {
144+
callable.reset();
145+
146+
uint32 c = callable.fooCount();
147+
assertEq(callable.lastCaller(), address(bytes20(0)));
148+
149+
uint value = 1;
150+
vm.deal(address(executor), value);
151+
152+
testExecute(
153+
address(callable),
154+
abi.encodeWithSelector(ICallable.fooPayable.selector),
155+
1,
156+
value
157+
);
158+
assertEq(callable.fooCount(), c + 1);
159+
assertEq(callable.lastCaller(), address(executor));
160+
assertEq(address(executor).balance, 0);
161+
assertEq(address(callable).balance, value);
162+
// Sanity check to make sure the check above is meaningful.
163+
assert(address(executor) != address(this));
164+
}
165+
166+
function testCallWithValueInsufficientBalance() public {
167+
callable.reset();
168+
169+
assertEq(callable.lastCaller(), address(bytes20(0)));
170+
171+
uint value = 5;
172+
vm.deal(address(executor), 1);
173+
174+
bytes memory payload = abi.encodePacked(
175+
uint32(0x5054474d),
176+
PythGovernanceInstructions.GovernanceModule.EvmExecutor,
177+
Executor.ExecutorAction.Execute,
178+
CHAIN_ID,
179+
address(executor),
180+
address(callable),
181+
value,
182+
abi.encodeWithSelector(ICallable.fooPayable.selector)
183+
);
184+
185+
bytes memory vaa = generateVaa(
186+
uint32(block.timestamp),
187+
OWNER_CHAIN_ID,
188+
OWNER_EMITTER,
189+
1,
190+
payload,
191+
NUM_SIGNERS
192+
);
193+
194+
vm.expectRevert();
195+
executor.execute(vaa);
196+
}
197+
138198
function testCallWithArgsSucceeds() public {
139199
callable.reset();
140200

@@ -143,10 +203,34 @@ contract ExecutorTest is Test, WormholeTestUtils {
143203
testExecute(
144204
address(callable),
145205
abi.encodeWithSelector(ICallable.fooWithArgs.selector, 17),
146-
1
206+
1,
207+
0
208+
);
209+
assertEq(callable.fooCount(), c + 17);
210+
assertEq(callable.lastCaller(), address(executor));
211+
// Sanity check to make sure the check above is meaningful.
212+
assert(address(executor) != address(this));
213+
}
214+
215+
function testCallWithArgsAndValueSucceeds() public {
216+
callable.reset();
217+
218+
uint32 c = callable.fooCount();
219+
assertEq(callable.lastCaller(), address(bytes20(0)));
220+
221+
uint value = 1;
222+
vm.deal(address(executor), value);
223+
224+
testExecute(
225+
address(callable),
226+
abi.encodeWithSelector(ICallable.fooPayableWithArgs.selector, 17),
227+
1,
228+
value
147229
);
148230
assertEq(callable.fooCount(), c + 17);
149231
assertEq(callable.lastCaller(), address(executor));
232+
assertEq(address(executor).balance, 0);
233+
assertEq(address(callable).balance, value);
150234
// Sanity check to make sure the check above is meaningful.
151235
assert(address(executor) != address(this));
152236
}
@@ -156,7 +240,8 @@ contract ExecutorTest is Test, WormholeTestUtils {
156240
testExecute(
157241
address(callable),
158242
abi.encodeWithSelector(ICallable.foo.selector),
159-
1
243+
1,
244+
0
160245
);
161246
assertEq(callable.fooCount(), c + 1);
162247
}
@@ -178,6 +263,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
178263
CHAIN_ID,
179264
address(executor),
180265
address(callable),
266+
uint(0),
181267
abi.encodeWithSelector(ICallable.foo.selector)
182268
);
183269

@@ -205,6 +291,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
205291
CHAIN_ID,
206292
address(executor),
207293
address(callable),
294+
uint(0),
208295
abi.encodeWithSelector(ICallable.foo.selector)
209296
);
210297

@@ -229,6 +316,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
229316
CHAIN_ID,
230317
address(executor),
231318
address(callable),
319+
uint(0),
232320
abi.encodeWithSelector(ICallable.foo.selector)
233321
);
234322

@@ -249,7 +337,8 @@ contract ExecutorTest is Test, WormholeTestUtils {
249337
testExecute(
250338
address(callable),
251339
abi.encodeWithSelector(ICallable.foo.selector),
252-
3
340+
3,
341+
0
253342
);
254343

255344
bytes memory payload = abi.encodePacked(
@@ -259,6 +348,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
259348
CHAIN_ID,
260349
address(executor),
261350
address(callable),
351+
uint(0),
262352
abi.encodeWithSelector(ICallable.foo.selector)
263353
);
264354

@@ -278,7 +368,8 @@ contract ExecutorTest is Test, WormholeTestUtils {
278368
testExecute(
279369
address(callable),
280370
abi.encodeWithSelector(ICallable.foo.selector),
281-
4
371+
4,
372+
0
282373
);
283374
assertEq(callable.fooCount(), 1);
284375
}
@@ -291,6 +382,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
291382
CHAIN_ID,
292383
address(executor),
293384
address(callable),
385+
uint(0),
294386
abi.encodeWithSelector(ICallable.foo.selector)
295387
);
296388

@@ -320,6 +412,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
320412
uint16(3),
321413
address(executor),
322414
address(callable),
415+
uint(0),
323416
abi.encodeWithSelector(ICallable.foo.selector)
324417
);
325418

@@ -344,6 +437,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
344437
CHAIN_ID,
345438
address(0x1),
346439
address(callable),
440+
uint(0),
347441
abi.encodeWithSelector(ICallable.foo.selector)
348442
);
349443

@@ -368,6 +462,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
368462
CHAIN_ID,
369463
address(executor),
370464
address(callable),
465+
uint(0),
371466
abi.encodeWithSelector(ICallable.foo.selector)
372467
);
373468

@@ -392,6 +487,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
392487
CHAIN_ID,
393488
address(executor),
394489
address(callable),
490+
uint(0),
395491
abi.encodeWithSelector(ICallable.reverts.selector)
396492
);
397493

@@ -416,6 +512,7 @@ contract ExecutorTest is Test, WormholeTestUtils {
416512
CHAIN_ID,
417513
address(executor),
418514
address(100),
515+
uint(0),
419516
abi.encodeWithSelector(ICallable.foo.selector)
420517
);
421518

@@ -436,8 +533,12 @@ contract ExecutorTest is Test, WormholeTestUtils {
436533
interface ICallable {
437534
function foo() external;
438535

536+
function fooPayable() external payable;
537+
439538
function fooWithArgs(uint32 inc) external;
440539

540+
function fooPayableWithArgs(uint32 inc) external payable;
541+
441542
function reverts() external;
442543

443544
function reset() external;
@@ -459,11 +560,21 @@ contract TestCallable is ICallable {
459560
lastCaller = msg.sender;
460561
}
461562

563+
function fooPayable() external payable override {
564+
fooCount += 1;
565+
lastCaller = msg.sender;
566+
}
567+
462568
function fooWithArgs(uint32 inc) external override {
463569
fooCount += inc;
464570
lastCaller = msg.sender;
465571
}
466572

573+
function fooPayableWithArgs(uint32 inc) external payable override {
574+
fooCount += inc;
575+
lastCaller = msg.sender;
576+
}
577+
467578
function reverts() external override {
468579
revert("call should revert");
469580
}

0 commit comments

Comments
 (0)