Skip to content

Commit dc3226b

Browse files
committed
more tests
1 parent 36de1de commit dc3226b

File tree

3 files changed

+172
-1
lines changed

3 files changed

+172
-1
lines changed

test/UniversalBridgeV1.t.sol

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { IModularCore } from "lib/modular-contracts/src/interface/IModularCore.s
1010
import { LibClone } from "lib/solady/src/utils/LibClone.sol";
1111
import { MockERC20 } from "./utils/MockERC20.sol";
1212
import { MockTarget } from "./utils/MockTarget.sol";
13+
import { MockTargetNonSpender } from "./utils/MockTargetNonSpender.sol";
14+
import { MockSpender } from "./utils/MockSpender.sol";
1315

1416
contract UniversalBridgeTest is Test {
1517
event TransactionInitiated(
@@ -25,6 +27,8 @@ contract UniversalBridgeTest is Test {
2527
UniversalBridgeV1 internal bridge;
2628
MockERC20 internal mockERC20;
2729
MockTarget internal mockTarget;
30+
MockTargetNonSpender internal mockTargetNonSpender;
31+
MockSpender internal mockSpender;
2832

2933
address payable internal owner;
3034
address payable internal protocolFeeRecipient;
@@ -63,6 +67,8 @@ contract UniversalBridgeTest is Test {
6367

6468
mockERC20 = new MockERC20("Token", "TKN");
6569
mockTarget = new MockTarget();
70+
mockSpender = new MockSpender();
71+
mockTargetNonSpender = new MockTargetNonSpender(address(mockSpender));
6672

6773
// fund the sender
6874
mockERC20.mint(sender, 1000 ether);
@@ -123,6 +129,42 @@ contract UniversalBridgeTest is Test {
123129
assertEq(mockERC20.balanceOf(receiver), receiverBalanceBefore + sendValue);
124130
}
125131

132+
function test_initiateTransaction_erc20_differentSpender() public {
133+
bytes memory targetCalldata = _buildMockTargetCalldata(sender, receiver, address(mockERC20), sendValue, "");
134+
135+
// approve amount to bridge contract
136+
vm.prank(sender);
137+
mockERC20.approve(address(bridge), sendValueWithFees);
138+
139+
bytes32 _transactionId = keccak256("transaction ID");
140+
141+
// state/balances before sending transaction
142+
uint256 protocolFeeRecipientBalanceBefore = mockERC20.balanceOf(protocolFeeRecipient);
143+
uint256 developerBalanceBefore = mockERC20.balanceOf(developer);
144+
uint256 senderBalanceBefore = mockERC20.balanceOf(sender);
145+
uint256 receiverBalanceBefore = mockERC20.balanceOf(receiver);
146+
147+
// send transaction
148+
vm.prank(sender);
149+
bridge.initiateTransaction(
150+
_transactionId,
151+
address(mockERC20),
152+
sendValue,
153+
payable(address(mockTargetNonSpender)),
154+
payable(address(mockSpender)),
155+
developer,
156+
developerFeeBps,
157+
targetCalldata,
158+
""
159+
);
160+
161+
// check balances after transaction
162+
assertEq(mockERC20.balanceOf(protocolFeeRecipient), protocolFeeRecipientBalanceBefore + expectedProtocolFee);
163+
assertEq(mockERC20.balanceOf(developer), developerBalanceBefore + expectedDeveloperFee);
164+
assertEq(mockERC20.balanceOf(sender), senderBalanceBefore - sendValueWithFees);
165+
assertEq(mockERC20.balanceOf(receiver), receiverBalanceBefore + sendValue);
166+
}
167+
126168
function test_initiateTransaction_erc20_directTransfer() public {
127169
// approve amount to bridge contract
128170
vm.prank(sender);
@@ -146,7 +188,6 @@ contract UniversalBridgeTest is Test {
146188
payable(address(0)),
147189
developer,
148190
developerFeeBps,
149-
// true,
150191
"",
151192
""
152193
);
@@ -196,6 +237,44 @@ contract UniversalBridgeTest is Test {
196237
assertEq(receiver.balance, receiverBalanceBefore + sendValue);
197238
}
198239

240+
function test_initiateTransaction_nativeToken_differentSpender() public {
241+
bytes memory targetCalldata = _buildMockTargetCalldata(
242+
sender,
243+
receiver,
244+
address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE),
245+
sendValue,
246+
""
247+
);
248+
249+
bytes32 _transactionId = keccak256("transaction ID");
250+
251+
// state/balances before sending transaction
252+
uint256 protocolFeeRecipientBalanceBefore = protocolFeeRecipient.balance;
253+
uint256 developerBalanceBefore = developer.balance;
254+
uint256 senderBalanceBefore = sender.balance;
255+
uint256 receiverBalanceBefore = receiver.balance;
256+
257+
// send transaction
258+
vm.prank(sender);
259+
bridge.initiateTransaction{ value: sendValueWithFees }(
260+
_transactionId,
261+
address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE),
262+
sendValue,
263+
payable(address(mockTargetNonSpender)),
264+
payable(address(mockSpender)),
265+
developer,
266+
developerFeeBps,
267+
targetCalldata,
268+
""
269+
);
270+
271+
// check balances after transaction
272+
assertEq(protocolFeeRecipient.balance, protocolFeeRecipientBalanceBefore + expectedProtocolFee);
273+
assertEq(developer.balance, developerBalanceBefore + expectedDeveloperFee);
274+
assertEq(sender.balance, senderBalanceBefore - sendValueWithFees);
275+
assertEq(receiver.balance, receiverBalanceBefore + sendValue);
276+
}
277+
199278
function test_initiateTransaction_nativeToken_directTransfer() public {
200279
bytes memory targetCalldata = "";
201280

test/utils/MockSpender.sol

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "lib/solady/src/tokens/ERC20.sol";
5+
import "lib/forge-std/src/console.sol";
6+
7+
contract MockSpender {
8+
event TargetLog(address sender, address receiver, address tokenAddress, uint256 tokenAmount, string message);
9+
10+
address private constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
11+
12+
function decodeData(bytes memory data) private pure returns (address, address, address, uint256, string memory) {
13+
return abi.decode(data, (address, address, address, uint256, string));
14+
}
15+
16+
function performERC20Action(
17+
address gateway,
18+
address sender,
19+
address payable receiver,
20+
address tokenAddress,
21+
uint256 tokenAmount,
22+
string memory message
23+
) private {
24+
emit TargetLog(sender, receiver, tokenAddress, tokenAmount, message);
25+
console.log("Transferring %s erc20 tokens from %s to %s", tokenAmount, sender, receiver);
26+
27+
require(ERC20(tokenAddress).transferFrom(gateway, receiver, tokenAmount), "Token transfer failed");
28+
}
29+
30+
function performNativeTokenAction(
31+
address gateway,
32+
address sender,
33+
address payable receiver,
34+
address tokenAddress,
35+
uint256 tokenAmount,
36+
string memory message
37+
) private {
38+
emit TargetLog(sender, receiver, tokenAddress, tokenAmount, message);
39+
console.log("Transferring %s native tokens from %s to %s", tokenAmount, sender, receiver);
40+
(bool sent, ) = receiver.call{ value: msg.value }("");
41+
require(sent, "Failed to send Ether");
42+
}
43+
44+
fallback() external payable {
45+
require(msg.data.length > 0, "data required");
46+
(address gateway, bytes memory data) = abi.decode(msg.data, (address, bytes));
47+
(
48+
address sender,
49+
address receiver,
50+
address tokenAddress,
51+
uint256 tokenAmount,
52+
string memory message
53+
) = decodeData(data);
54+
55+
if (tokenAddress == NATIVE_TOKEN_ADDRESS) {
56+
console.log("Calling native token action!");
57+
performNativeTokenAction(gateway, payable(sender), payable(receiver), tokenAddress, tokenAmount, message);
58+
} else {
59+
console.log("Calling erc20 token action!");
60+
performERC20Action(gateway, payable(sender), payable(receiver), tokenAddress, tokenAmount, message);
61+
}
62+
}
63+
64+
receive() external payable {}
65+
}

test/utils/MockTargetNonSpender.sol

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "lib/solady/src/tokens/ERC20.sol";
5+
import "lib/forge-std/src/console.sol";
6+
7+
contract MockTargetNonSpender {
8+
address spender;
9+
10+
constructor(address _spender) {
11+
spender = _spender;
12+
}
13+
14+
fallback() external payable {
15+
(bool success, bytes memory response) = spender.call{ value: msg.value }(abi.encode(msg.sender, msg.data));
16+
if (!success) {
17+
if (response.length > 0) {
18+
assembly {
19+
let returndata_size := mload(response)
20+
revert(add(32, response), returndata_size)
21+
}
22+
} else {
23+
revert("Failed at target");
24+
}
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)