Skip to content

Commit 57e308e

Browse files
committed
Implement wrap/unwrap all functions; always wrap/unwrap all in QuarkBuilder
1 parent 8b39c27 commit 57e308e

16 files changed

+131
-144
lines changed

src/WrapperScripts.sol

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@ contract WrapperActions {
1010
IWETH(weth).deposit{value: amount}();
1111
}
1212

13-
function wrapETHUpTo(address weth, uint256 targetAmount) external payable {
14-
uint256 currentBalance = IERC20(weth).balanceOf(address(this));
15-
if (currentBalance < targetAmount) {
16-
IWETH(weth).deposit{value: targetAmount - currentBalance}();
13+
function wrapAllETH(address weth) external payable {
14+
uint256 ethBalance = address(this).balance;
15+
if (ethBalance > 0) {
16+
IWETH(weth).deposit{value: ethBalance}();
1717
}
1818
}
1919

2020
function unwrapWETH(address weth, uint256 amount) external {
2121
IWETH(weth).withdraw(amount);
2222
}
2323

24-
function unwrapWETHUpTo(address weth, uint256 targetAmount) external {
25-
uint256 currentBalance = address(this).balance;
26-
if (currentBalance < targetAmount) {
27-
IWETH(weth).withdraw(targetAmount - currentBalance);
24+
function unwrapAllWETH(address weth) external payable {
25+
uint256 wethBalance = IERC20(weth).balanceOf(address(this));
26+
if (wethBalance > 0) {
27+
IWETH(weth).withdraw(wethBalance);
2828
}
2929
}
3030

@@ -33,7 +33,22 @@ contract WrapperActions {
3333
IWstETH(wstETH).wrap(amount);
3434
}
3535

36+
function wrapAllLidoStETH(address wstETH, address stETH) external payable {
37+
uint256 stETHBalance = IERC20(stETH).balanceOf(address(this));
38+
if (stETHBalance > 0) {
39+
IERC20(stETH).approve(wstETH, stETHBalance);
40+
IWstETH(wstETH).wrap(stETHBalance);
41+
}
42+
}
43+
3644
function unwrapLidoWstETH(address wstETH, uint256 amount) external {
3745
IWstETH(wstETH).unwrap(amount);
3846
}
47+
48+
function unwrapAllLidoWstETH(address wstETH) external {
49+
uint256 wstETHBalance = IERC20(wstETH).balanceOf(address(this));
50+
if (wstETHBalance > 0) {
51+
IWstETH(wstETH).unwrap(wstETHBalance);
52+
}
53+
}
3954
}

src/builder/BridgeRoutes.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ library Across {
208208
uint256 bridgedAmount = HashMap.contains(assetsBridged, abi.encode(assetSymbol))
209209
? HashMap.getUint256(assetsBridged, abi.encode(assetSymbol))
210210
: 0;
211-
return bridgedAmount != 0
211+
return bridgedAmount > 0
212212
&& (Strings.stringEqIgnoreCase(assetSymbol, "ETH") || Strings.stringEqIgnoreCase(assetSymbol, "WETH"));
213213
}
214214
}

src/builder/QuarkBuilderBase.sol

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ contract QuarkBuilderBase {
3737

3838
/* ===== Constants ===== */
3939

40-
string constant VERSION = "0.2.0";
40+
string constant VERSION = "0.2.1";
4141

4242
/* ===== Custom Errors ===== */
4343

@@ -234,10 +234,8 @@ contract QuarkBuilderBase {
234234
: 0;
235235
// Note: Right now, ETH/WETH is only bridged via Across. Across has a weird quirk where it will send ETH to EOAs and
236236
// WETH to contracts. Since the QuarkBuilder cannot know if a QuarkWallet is deployed before the operation is actually
237-
// executed on-chain, it needs to use the "wrap up to" script because it cannot know how much to wrap ahead of time.
238-
bool useWrapUpTo;
237+
// executed on-chain, we need to assume there is no supplemental balance that arrives on the destination chain.
239238
if (Across.isNonDeterministicBridgeAction(assetsBridged, assetSymbolOut)) {
240-
useWrapUpTo = true;
241239
supplementalBalance = 0;
242240
}
243241

@@ -247,13 +245,12 @@ contract QuarkBuilderBase {
247245
chainAccountsList: chainAccountsList,
248246
payment: payment,
249247
assetSymbol: assetSymbolOut,
250-
amount: actionIntent.amountOuts[i],
248+
amountNeeded: actionIntent.amountOuts[i],
251249
supplementalBalance: supplementalBalance,
252250
chainId: actionIntent.chainId,
253251
account: actionIntent.actor,
254252
blockTimestamp: actionIntent.blockTimestamp,
255-
useQuotecall: actionIntent.useQuotecall,
256-
useWrapUpTo: useWrapUpTo
253+
useQuotecall: actionIntent.useQuotecall
257254
});
258255
}
259256
}
@@ -415,41 +412,30 @@ contract QuarkBuilderBase {
415412
Accounts.ChainAccounts[] memory chainAccountsList,
416413
PaymentInfo.Payment memory payment,
417414
string memory assetSymbol,
418-
uint256 amount,
415+
uint256 amountNeeded,
419416
uint256 supplementalBalance,
420417
uint256 chainId,
421418
address account,
422419
uint256 blockTimestamp,
423-
bool useQuotecall,
424-
bool useWrapUpTo
420+
bool useQuotecall
425421
) internal pure {
426422
// Check if inserting wrapOrUnwrap action is necessary
427423
uint256 assetBalanceOnChain =
428424
Accounts.getBalanceOnChain(assetSymbol, chainId, chainAccountsList) + supplementalBalance;
429-
if (assetBalanceOnChain < amount && TokenWrapper.hasWrapperContract(chainId, assetSymbol)) {
425+
if (assetBalanceOnChain < amountNeeded && TokenWrapper.hasWrapperContract(chainId, assetSymbol)) {
430426
// If the asset has a wrapper counterpart, wrap/unwrap the token to cover the amount needed for the intent
431427
string memory counterpartSymbol = TokenWrapper.getWrapperCounterpartSymbol(chainId, assetSymbol);
432428

433429
// Wrap/unwrap the token to cover the amount
434-
uint256 amountToWrap;
435-
if (useWrapUpTo) {
436-
// If we are using the "wrap up to script", then the `amountToWrap` should be the entire amount needed
437-
// for the intent
438-
amountToWrap = amount;
439-
} else {
440-
// If we aren't using the "wrap up to" script, then we need to subtract the current balance from the
441-
// amount to wrap
442-
amountToWrap = amount - assetBalanceOnChain;
443-
}
444430
(IQuarkWallet.QuarkOperation memory wrapOrUnwrapOperation, Actions.Action memory wrapOrUnwrapAction) =
445431
Actions.wrapOrUnwrapAsset(
446432
Actions.WrapOrUnwrapAsset({
447433
chainAccountsList: chainAccountsList,
448434
assetSymbol: counterpartSymbol,
449-
amount: amountToWrap,
435+
// This is just to indicate we plan to wrap all
436+
amount: type(uint256).max,
450437
chainId: chainId,
451438
sender: account,
452-
useWrapUpTo: useWrapUpTo,
453439
blockTimestamp: blockTimestamp
454440
}),
455441
payment,

src/builder/TokenWrapper.sol

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -108,67 +108,50 @@ library TokenWrapper {
108108
return Strings.stringEqIgnoreCase(tokenSymbol, getKnownWrapperTokenPair(chainId, tokenSymbol).wrappedSymbol);
109109
}
110110

111-
function encodeActionToWrapOrUnwrap(uint256 chainId, string memory tokenSymbol, uint256 amount, bool useWrapUpTo)
111+
function encodeActionToWrapOrUnwrap(uint256 chainId, string memory tokenSymbol)
112112
internal
113113
pure
114114
returns (bytes memory)
115115
{
116116
KnownWrapperTokenPair memory pair = getKnownWrapperTokenPair(chainId, tokenSymbol);
117117
if (isWrappedToken(chainId, tokenSymbol)) {
118-
return encodeActionToUnwrapToken(chainId, tokenSymbol, amount, useWrapUpTo);
118+
return encodeActionToUnwrapToken(chainId, tokenSymbol);
119119
} else {
120-
return encodeActionToWrapToken(chainId, tokenSymbol, pair.underlyingToken, amount, useWrapUpTo);
120+
return encodeActionToWrapToken(chainId, tokenSymbol, pair.underlyingToken);
121121
}
122122
}
123123

124-
function encodeActionToWrapToken(
125-
uint256 chainId,
126-
string memory tokenSymbol,
127-
address tokenAddress,
128-
uint256 amount,
129-
bool useWrapUpTo
130-
) internal pure returns (bytes memory) {
124+
function encodeActionToWrapToken(uint256 chainId, string memory tokenSymbol, address tokenAddress)
125+
internal
126+
pure
127+
returns (bytes memory)
128+
{
131129
if (Strings.stringEqIgnoreCase(tokenSymbol, "ETH")) {
132-
if (useWrapUpTo) {
133-
return abi.encodeWithSelector(
134-
WrapperActions.wrapETHUpTo.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper, amount
135-
);
136-
} else {
137-
return abi.encodeWithSelector(
138-
WrapperActions.wrapETH.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper, amount
139-
);
140-
}
130+
return abi.encodeWithSelector(
131+
WrapperActions.wrapAllETH.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper
132+
);
141133
} else if (Strings.stringEqIgnoreCase(tokenSymbol, "stETH")) {
142134
return abi.encodeWithSelector(
143-
WrapperActions.wrapLidoStETH.selector,
135+
WrapperActions.wrapAllLidoStETH.selector,
144136
getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper,
145-
tokenAddress,
146-
amount
137+
tokenAddress
147138
);
148139
}
149140
revert NotWrappable();
150141
}
151142

152-
function encodeActionToUnwrapToken(uint256 chainId, string memory tokenSymbol, uint256 amount, bool useWrapUpTo)
143+
function encodeActionToUnwrapToken(uint256 chainId, string memory tokenSymbol)
153144
internal
154145
pure
155146
returns (bytes memory)
156147
{
157148
if (Strings.stringEqIgnoreCase(tokenSymbol, "WETH")) {
158-
if (useWrapUpTo) {
159-
return abi.encodeWithSelector(
160-
WrapperActions.unwrapWETHUpTo.selector,
161-
getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper,
162-
amount
163-
);
164-
} else {
165-
return abi.encodeWithSelector(
166-
WrapperActions.unwrapWETH.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper, amount
167-
);
168-
}
149+
return abi.encodeWithSelector(
150+
WrapperActions.unwrapAllWETH.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper
151+
);
169152
} else if (Strings.stringEqIgnoreCase(tokenSymbol, "wstETH")) {
170153
return abi.encodeWithSelector(
171-
WrapperActions.unwrapLidoWstETH.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper, amount
154+
WrapperActions.unwrapAllLidoWstETH.selector, getKnownWrapperTokenPair(chainId, tokenSymbol).wrapper
172155
);
173156
}
174157
revert NotUnwrappable();

src/builder/actions/Actions.sol

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ library Actions {
118118
uint256 amount;
119119
uint256 chainId;
120120
address sender;
121-
bool useWrapUpTo;
122121
uint256 blockTimestamp;
123122
}
124123

@@ -1491,9 +1490,7 @@ library Actions {
14911490
nonce: accountSecret.nonceSecret,
14921491
isReplayable: false,
14931492
scriptAddress: CodeJarHelper.getCodeAddress(type(WrapperActions).creationCode),
1494-
scriptCalldata: TokenWrapper.encodeActionToWrapOrUnwrap(
1495-
wrapOrUnwrap.chainId, wrapOrUnwrap.assetSymbol, wrapOrUnwrap.amount, wrapOrUnwrap.useWrapUpTo
1496-
),
1493+
scriptCalldata: TokenWrapper.encodeActionToWrapOrUnwrap(wrapOrUnwrap.chainId, wrapOrUnwrap.assetSymbol),
14971494
scriptSources: scriptSources,
14981495
expiry: wrapOrUnwrap.blockTimestamp + STANDARD_EXPIRY_BUFFER
14991496
});

src/interfaces/IWstETH.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
pragma solidity 0.8.27;
33

44
interface IWstETH {
5-
function wrap(uint256 amount) external returns (uint256);
6-
function unwrap(uint256 amount) external returns (uint256);
5+
function wrap(uint256 stETHAmount) external returns (uint256);
6+
function unwrap(uint256 wstETHAmount) external returns (uint256);
77
}

0 commit comments

Comments
 (0)