Skip to content

Commit d3ed7cd

Browse files
committed
refactor: TrebleSwap test structure for reuse
1 parent b258503 commit d3ed7cd

File tree

1 file changed

+140
-62
lines changed

1 file changed

+140
-62
lines changed

test/TrebleSwap.t.sol

Lines changed: 140 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,43 @@ contract TrebleSwapTest is BaseTest {
4040
UserOperation userOp;
4141
SolverOperation[] solverOps;
4242
DAppOperation dAppOp;
43+
uint256 blockBefore; // block before real tx happened
44+
bool nativeInput;
45+
bool nativeOutput;
4346
}
4447

45-
TrebleSwapDAppControl public trebleSwapControl;
46-
Sig public sig;
47-
Args public args;
48+
struct BeforeAndAfterVars {
49+
uint256 userInputTokenBalance;
50+
uint256 userOutputTokenBalance;
51+
uint256 solverInputTokenBalance;
52+
uint256 solverOutputTokenBalance;
53+
uint256 burnAddressTrebBalance;
54+
uint256 atlasGasSurcharge;
55+
}
4856

4957
// Odos Router v2 on Base
50-
address public constant ODOS_ROUTER = 0x19cEeAd7105607Cd444F5ad10dd51356436095a1;
58+
address constant ODOS_ROUTER = 0x19cEeAd7105607Cd444F5ad10dd51356436095a1;
59+
address constant ETH = address(0);
60+
address constant BURN = address(0xdead);
5161

5262
// Base ERC20 addresses
5363
IERC20 bWETH = IERC20(0x4200000000000000000000000000000000000006);
5464
IERC20 USDC = IERC20(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913);
5565
IERC20 WUF = IERC20(0x4da78059D97f155E18B37765e2e042270f4E0fC4);
56-
IERC20 TREB = IERC20(0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed);
66+
IERC20 TREB = IERC20(0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed); // TODO DEGEN for now, replace when TREB available
5767

68+
TrebleSwapDAppControl trebleSwapControl;
5869
address executionEnvironment;
5970

71+
Sig sig;
72+
Args args;
73+
SwapTokenInfo swapInfo;
74+
BeforeAndAfterVars beforeVars;
75+
6076
function setUp() public virtual override {
6177
// Fork Base
6278
vm.createSelectFork(vm.envString("BASE_RPC_URL"), 18_906_794);
79+
// TODO make this before all tx blocks in this file - atlas deployed before
6380

6481
_BaseTest_DeployAtlasContracts();
6582

@@ -82,99 +99,160 @@ contract TrebleSwapTest is BaseTest {
8299
vm.label(address(TREB), "DEGEN"); // TODO change label to TREB when TREB token available
83100
}
84101

85-
function testTrebleSwap_swapUsdcToWuf() public {
86-
// Based on: https://basescan.org/tx/0x0ef4a9c24bbede2b39e12f5e5417733fa8183f372e41ee099c2c7523064c1b55
87-
// Swaps 197.2 USDC for 200,064,568.9293 WUF
102+
// ---------------------------------------------------- //
103+
// Scenario Tests //
104+
// ---------------------------------------------------- //
105+
106+
function testTrebleSwap_Metacall_Erc20ToErc20_ZeroSolvers() public {
107+
// Tx: https://basescan.org/tx/0x0ef4a9c24bbede2b39e12f5e5417733fa8183f372e41ee099c2c7523064c1b55
108+
// Swaps 197.2 USDC for at least 198,080,836.0295 WUF
109+
110+
args.blockBefore = 18_906_794;
111+
args.nativeInput = false;
112+
args.nativeOutput = false;
113+
swapInfo = SwapTokenInfo({
114+
inputToken: address(USDC),
115+
inputAmount: 197_200_000,
116+
outputToken: address(WUF),
117+
outputMin: 1_980_808_360_295
118+
});
119+
vm.roll(args.blockBefore);
120+
121+
// Modify swapCompact() calldata to replace original caller (0xa4a9220dE44D699f453DdF7F7630A96cDEdf6463) with
122+
// user's Execution Environment address:
123+
bytes memory calldataPart1 =
124+
hex"83bd37f9000400014da78059d97f155e18b37765e2e042270f4e0fc4040bc108800601d1d9f50a5a028f5c0001f73f77f9466da712590ae432a80f07fd50a7de600001616535324976f8dbcef19df0705b95ace86ebb480001";
125+
bytes memory calldataPart2 =
126+
hex"0000000006020207003401000001020180000005020a0004040500000301010003060119ff0000000000000000000000000000000000000000000000000000000000000000616535324976f8dbcef19df0705b95ace86ebb48833589fcd6edb6e08f4c7c32d4f71b54bda02913569d81c17b5b4ac08929dc1769b8e39668d3ae29f6c0a374a483101e04ef5f7ac9bd15d9142bac95d9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca42000000000000000000000000000000000000060000000000000000";
127+
bytes memory swapCompactCalldata = abi.encodePacked(calldataPart1, executionEnvironment, calldataPart2);
128+
129+
_checkActualCalldataMatchesExpected(swapCompactCalldata);
130+
_buildUserOp(swapCompactCalldata);
131+
// no solverOps
132+
_buildAndSignDAppOp();
133+
_setBalancesAndApprovals();
134+
_checkSimulationsPass();
135+
_doMetacallAndChecks({ winningSolverEOA: address(0), winningSolver: address(0) });
136+
}
88137

89-
// Fork Base at block before USDC -> WUF swap on Odos
138+
function testTrebleSwap_Metacall_EthToErc20_ZeroSolvers() public {
139+
vm.skip(true);
90140

91-
// USDC: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
92-
// WUF: 0x4da78059D97f155E18B37765e2e042270f4E0fC4
141+
// Tx 1: https://basescan.org/tx/0xdc4f046b052cfaf227ccb1ad83b4a86521cf4f2bcf5343793f22fc39f61dfe02
93142

94-
// Original calldata from tx above:
95-
// 0x83bd37f9 -> swapCompact selector
96-
// 0004 -> input token -> address list [USDC]
97-
// 0001 4da78059d97f155e18b37765e2e042270f4e0fc4 -> output token -> calldata address [WUF]
98-
// 04 0bc10880 -> input amount -> length = 4 bytes, value = 197200000
99-
// 0601d1d9f50a5a028f5c0001f73f77f9466da712590ae432a80f07fd50a7de600001616535324976f8dbcef19df0705b95ace86ebb480001a4a9220de44d699f453ddf7f7630a96cdedf64630000000006020207003401000001020180000005020a0004040500000301010003060119ff0000000000000000000000000000000000000000000000000000000000000000616535324976f8dbcef19df0705b95ace86ebb48833589fcd6edb6e08f4c7c32d4f71b54bda02913569d81c17b5b4ac08929dc1769b8e39668d3ae29f6c0a374a483101e04ef5f7ac9bd15d9142bac95d9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca42000000000000000000000000000000000000060000000000000000
143+
// swapCompact calldata:
144+
// 83bd37f900000004072386f26fc10000040180ef410147ae0001f73f77f9466da712590ae432a80f07fd50a7de60000000013eb8b2f4584c642a43ed5cad2f83182de41b5de2000000010301020300040101020a0001010201ff000000000000000000000000000000000074cb6260be6f31965c239df6d6ef2ac2b5d4f0204200000000000000000000000000000000000006000000000000000000000000000000000000000000000000
100145

101-
// Replace caller address (0xa4a9220dE44D699f453DdF7F7630A96cDEdf6463)
102-
// with EE address: (0x31b9EdCc7937b5d5E434D45aaF1F4f98407f45eb)
103-
// Build userOp.data for swapCompact call
104-
bytes memory swapCompactCalldata =
105-
hex"83bd37f9000400014da78059d97f155e18b37765e2e042270f4e0fc4040bc108800601d1d9f50a5a028f5c0001f73f77f9466da712590ae432a80f07fd50a7de600001616535324976f8dbcef19df0705b95ace86ebb48000131b9EdCc7937b5d5E434D45aaF1F4f98407f45eb0000000006020207003401000001020180000005020a0004040500000301010003060119ff0000000000000000000000000000000000000000000000000000000000000000616535324976f8dbcef19df0705b95ace86ebb48833589fcd6edb6e08f4c7c32d4f71b54bda02913569d81c17b5b4ac08929dc1769b8e39668d3ae29f6c0a374a483101e04ef5f7ac9bd15d9142bac95d9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca42000000000000000000000000000000000000060000000000000000";
146+
// From: 0x3EB8b2F4584c642a43eD5caD2F83182de41B5dE2
106147

107-
bytes memory encodedCall =
108-
abi.encodePacked(TrebleSwapDAppControl.decodeUserOpData.selector, swapCompactCalldata);
109-
(bool res, bytes memory returnData) = address(trebleSwapControl).staticcall(encodedCall);
148+
// Tx 2: https://basescan.org/tx/0xe138def4155bea056936038b9374546a366828ab8bf1233056f9e2fe4c6af999
110149

111-
console.log("res", res);
150+
// swapCompact calldata:
151+
// 0x83bd37f9000000050801b505fc9226ffb80910d5345f06a9650000028f5c0001f73f77f9466da712590ae432a80f07fd50a7de6000000001adf6918ed87a5d7ae334bb42ca2d98971b527306000000000401020500040101020a000202030100340101000104007ffffffaff00000000005fb33b095c6e739be19364ab408cd8f102262bb672ab388e2e2f6facef59e3c3fa2c4e29011c2d384200000000000000000000000000000000000006833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000
112152

113-
SwapTokenInfo memory swapInfo = abi.decode(returnData, (SwapTokenInfo));
153+
// From: 0xadF6918eD87a5D7aE334bB42Ca2d98971B527306
154+
}
114155

115-
// SwapTokenInfo memory swapInfo = decodeSwapCompactCalldata(swapCompactCalldata);
156+
// ---------------------------------------------------- //
157+
// Helper Functions //
158+
// ---------------------------------------------------- //
116159

117-
console.log("swapInfo.inputToken", swapInfo.inputToken);
118-
console.log("swapInfo.inputAmount", swapInfo.inputAmount);
119-
console.log("swapInfo.outputToken", swapInfo.outputToken);
120-
console.log("swapInfo.outputMin", swapInfo.outputMin);
160+
function _doMetacallAndChecks(address winningSolverEOA, address winningSolver) internal {
161+
bool auctionWonExpected = winningSolver != address(0);
162+
beforeVars.userInputTokenBalance = _balanceOf(swapInfo.inputToken, userEOA);
163+
beforeVars.userOutputTokenBalance = _balanceOf(swapInfo.outputToken, userEOA);
164+
beforeVars.solverInputTokenBalance = _balanceOf(swapInfo.inputToken, winningSolverEOA);
165+
beforeVars.solverOutputTokenBalance = _balanceOf(swapInfo.outputToken, winningSolverEOA);
166+
beforeVars.burnAddressTrebBalance = _balanceOf(address(TREB), BURN);
167+
beforeVars.atlasGasSurcharge = atlas.cumulativeSurcharge();
121168

122-
console.log("gas price:", tx.gasprice);
169+
vm.prank(userEOA);
170+
bool auctionWon = atlas.metacall{ value: 1e17 }(args.userOp, args.solverOps, args.dAppOp);
123171

124-
// Build userOp
172+
assertEq(auctionWon, auctionWonExpected, "auctionWon not as expected");
173+
174+
// Check user balance changes
175+
assertEq(
176+
_balanceOf(swapInfo.inputToken, userEOA),
177+
beforeVars.userInputTokenBalance - swapInfo.inputAmount,
178+
"wrong user input token balance change"
179+
);
180+
assertTrue(
181+
_balanceOf(swapInfo.outputToken, userEOA) >= beforeVars.userOutputTokenBalance + swapInfo.outputMin,
182+
"wrong user output token balance change"
183+
);
184+
}
185+
186+
function _checkSimulationsPass() internal {
187+
// TODO do all variations of sim calls here with checks
188+
}
189+
190+
function _checkActualCalldataMatchesExpected(bytes memory userOpData) internal {
191+
bytes memory encodedCall = abi.encodePacked(TrebleSwapDAppControl.decodeUserOpData.selector, userOpData);
192+
(bool res, bytes memory returnData) = address(trebleSwapControl).staticcall(encodedCall);
193+
assertEq(res, true, "calldata check failed in decode call");
194+
195+
SwapTokenInfo memory decodedInfo = abi.decode(returnData, (SwapTokenInfo));
196+
assertEq(decodedInfo.inputToken, swapInfo.inputToken, "inputToken mismatch");
197+
assertEq(decodedInfo.inputAmount, swapInfo.inputAmount, "inputAmount mismatch");
198+
assertEq(decodedInfo.outputToken, swapInfo.outputToken, "outputToken mismatch");
199+
assertEq(decodedInfo.outputMin, swapInfo.outputMin, "outputMin mismatch");
200+
}
201+
202+
function _setBalancesAndApprovals() internal {
203+
// User input token and Atlas approval
204+
if (args.nativeInput) {
205+
deal(userEOA, swapInfo.inputAmount);
206+
} else {
207+
deal(swapInfo.inputToken, userEOA, swapInfo.inputAmount);
208+
vm.prank(userEOA);
209+
IERC20(swapInfo.inputToken).approve(address(atlas), swapInfo.inputAmount);
210+
}
211+
212+
// TODO give solver contracts TREB for bids
213+
}
214+
215+
function _buildUserOp(bytes memory userOpData) internal {
125216
args.userOp = UserOperation({
126217
from: userEOA,
127218
to: address(atlas),
128-
value: 0,
219+
value: args.nativeInput ? swapInfo.inputAmount : 0,
129220
gas: 1_000_000,
130221
maxFeePerGas: tx.gasprice,
131222
nonce: 1,
132-
deadline: 18_906_796, // 1 block after tx happened
223+
deadline: args.blockBefore + 2,
133224
dapp: ODOS_ROUTER,
134225
control: address(trebleSwapControl),
135226
callConfig: trebleSwapControl.CALL_CONFIG(),
136227
sessionKey: address(0),
137-
data: swapCompactCalldata,
138-
signature: new bytes(0) // no sig - user will be bundler
139-
});
140-
141-
// No solverOp for now
228+
data: userOpData,
229+
signature: new bytes(0)
230+
});
231+
}
142232

143-
// Build DAppOperation
233+
function _buildAndSignDAppOp() internal {
144234
args.dAppOp = DAppOperation({
145235
from: governanceEOA,
146236
to: address(atlas),
147237
nonce: 1,
148-
deadline: 18_906_796, // 1 block after tx happened
238+
deadline: args.blockBefore + 2,
149239
control: address(trebleSwapControl),
150240
bundler: address(0),
151241
userOpHash: atlasVerification.getUserOperationHash(args.userOp),
152242
callChainHash: CallVerification.getCallChainHash(args.userOp, args.solverOps),
153243
signature: new bytes(0)
154244
});
155245

156-
// Gov signs dAppOp
157246
(sig.v, sig.r, sig.s) = vm.sign(governancePK, atlasVerification.getDAppOperationPayload(args.dAppOp));
158247
args.dAppOp.signature = abi.encodePacked(sig.r, sig.s, sig.v);
248+
}
159249

160-
// Mint userEOA enough USDC
161-
deal(address(USDC), userEOA, swapInfo.inputAmount);
162-
assertEq(USDC.balanceOf(userEOA), swapInfo.inputAmount);
163-
164-
console.log("User balances before:");
165-
console.log("USDC", USDC.balanceOf(userEOA));
166-
console.log("WUF", WUF.balanceOf(userEOA));
167-
168-
// User approves Atlas to take input token - USDC
169-
vm.startPrank(userEOA);
170-
USDC.approve(address(atlas), swapInfo.inputAmount);
171-
172-
bool auctionWon = atlas.metacall{ value: 1e17 }(args.userOp, args.solverOps, args.dAppOp);
173-
vm.stopPrank();
174-
175-
console.log("User balances after:");
176-
console.log("USDC", USDC.balanceOf(userEOA));
177-
console.log("WUF", WUF.balanceOf(userEOA));
250+
function _balanceOf(address token, address account) internal view returns (uint256) {
251+
if (token == ETH) {
252+
return account.balance;
253+
} else {
254+
return IERC20(token).balanceOf(account);
255+
}
178256
}
179257
}
180258

0 commit comments

Comments
 (0)