Skip to content

Commit 389f945

Browse files
authored
[TokenPaymaster] Support chains without WETH9 & Other Improvements (#670)
* [TokenPaymaster] Support chains without WETH9 For chains like Celo we can swap directly to it without unwrapping * Ability to update Oracle config & better cache price updates * expose _setOracleConfiguration * make configs public * Switch to swap-router-contracts interface * Create swap-router-contracts * move price update to validate fn
1 parent cf51bfa commit 389f945

File tree

7 files changed

+30
-13
lines changed

7 files changed

+30
-13
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,6 @@
5252
[submodule "lib/v3-core"]
5353
path = lib/v3-core
5454
url = https://github.com/uniswap/v3-core
55+
[submodule "lib/swap-router-contracts"]
56+
path = lib/swap-router-contracts
57+
url = https://github.com/Uniswap/swap-router-contracts

contracts/prebuilts/account/token-paymaster/TokenPaymaster.sol

+10-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
6868
IERC20Metadata _token,
6969
IEntryPoint _entryPoint,
7070
IERC20 _wrappedNative,
71-
ISwapRouter _uniswap,
71+
IV3SwapRouter _uniswap,
7272
TokenPaymasterConfig memory _tokenPaymasterConfig,
7373
OracleHelperConfig memory _oracleHelperConfig,
7474
UniswapHelperConfig memory _uniswapHelperConfig,
@@ -98,6 +98,10 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
9898
_setUniswapHelperConfiguration(_uniswapHelperConfig);
9999
}
100100

101+
function setOracleConfiguration(OracleHelperConfig memory _oracleHelperConfig) external onlyOwner {
102+
_setOracleConfiguration(_oracleHelperConfig);
103+
}
104+
101105
/// @notice Allows the contract owner to withdraw a specified amount of tokens from the contract.
102106
/// @param to The address to transfer the tokens to.
103107
/// @param amount The amount of tokens to transfer.
@@ -123,6 +127,10 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
123127
uint256 refundPostopCost = tokenPaymasterConfig.refundPostopCost;
124128
require(refundPostopCost < userOp.unpackPostOpGasLimit(), "TPM: postOpGasLimit too low");
125129
uint256 preChargeNative = requiredPreFund + (refundPostopCost * maxFeePerGas);
130+
131+
bool forceUpdate = (block.timestamp - cachedPriceTimestamp) > tokenPaymasterConfig.priceMaxAge;
132+
updateCachedPrice(forceUpdate);
133+
126134
// note: as price is in native-asset-per-token and we want more tokens increasing it means dividing it by markup
127135
uint256 cachedPriceWithMarkup = (cachedPrice * PRICE_DENOMINATOR) / priceMarkup;
128136
if (dataLength == 32) {
@@ -161,7 +169,7 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
161169
unchecked {
162170
uint256 priceMarkup = tokenPaymasterConfig.priceMarkup;
163171
(uint256 preCharge, address userOpSender) = abi.decode(context, (uint256, address));
164-
uint256 _cachedPrice = updateCachedPrice(false);
172+
uint256 _cachedPrice = cachedPrice;
165173
// note: as price is in native-asset-per-token and we want more tokens increasing it means dividing it by markup
166174
uint256 cachedPriceWithMarkup = (_cachedPrice * PRICE_DENOMINATOR) / priceMarkup;
167175
// Refund tokens based on actual gas cost

contracts/prebuilts/account/utils/OracleHelper.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ abstract contract OracleHelper {
4141
/// @notice The timestamp of a block when the cached price was updated
4242
uint48 public cachedPriceTimestamp;
4343

44-
OracleHelperConfig private oracleHelperConfig;
44+
OracleHelperConfig public oracleHelperConfig;
4545

4646
/// @notice The "10^(tokenOracle.decimals)" value used for the price calculation
4747
uint128 private tokenOracleDecimalPower;
@@ -54,7 +54,7 @@ abstract contract OracleHelper {
5454
_setOracleConfiguration(_oracleHelperConfig);
5555
}
5656

57-
function _setOracleConfiguration(OracleHelperConfig memory _oracleHelperConfig) private {
57+
function _setOracleConfiguration(OracleHelperConfig memory _oracleHelperConfig) internal {
5858
oracleHelperConfig = _oracleHelperConfig;
5959
require(_oracleHelperConfig.priceUpdateThreshold <= PRICE_DENOMINATOR, "TPM: update threshold too high");
6060
tokenOracleDecimalPower = uint128(10 ** oracleHelperConfig.tokenOracle.decimals());

contracts/prebuilts/account/utils/UniswapHelper.sol

+9-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pragma solidity ^0.8.23;
66
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
77
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
88

9-
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
9+
import "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol";
1010
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol";
1111

1212
abstract contract UniswapHelper {
@@ -19,23 +19,24 @@ abstract contract UniswapHelper {
1919
uint256 minSwapAmount;
2020
uint24 uniswapPoolFee;
2121
uint8 slippage;
22+
bool wethIsNativeAsset;
2223
}
2324

2425
/// @notice The Uniswap V3 SwapRouter contract
25-
ISwapRouter public immutable uniswap;
26+
IV3SwapRouter public immutable uniswap;
2627

2728
/// @notice The ERC20 token used for transaction fee payments
2829
IERC20Metadata public immutable token;
2930

3031
/// @notice The ERC-20 token that wraps the native asset for current chain
3132
IERC20 public immutable wrappedNative;
3233

33-
UniswapHelperConfig private uniswapHelperConfig;
34+
UniswapHelperConfig public uniswapHelperConfig;
3435

3536
constructor(
3637
IERC20Metadata _token,
3738
IERC20 _wrappedNative,
38-
ISwapRouter _uniswap,
39+
IV3SwapRouter _uniswap,
3940
UniswapHelperConfig memory _uniswapHelperConfig
4041
) {
4142
_token.approve(address(_uniswap), type(uint256).max);
@@ -85,6 +86,9 @@ abstract contract UniswapHelper {
8586
}
8687

8788
function unwrapWeth(uint256 amount) internal {
89+
if (uniswapHelperConfig.wethIsNativeAsset) {
90+
return;
91+
}
8892
IPeripheryPayments(address(uniswap)).unwrapWETH9(amount, address(this));
8993
}
9094

@@ -96,12 +100,11 @@ abstract contract UniswapHelper {
96100
uint256 amountOutMin,
97101
uint24 fee
98102
) internal returns (uint256 amountOut) {
99-
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams(
103+
IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter.ExactInputSingleParams(
100104
tokenIn, //tokenIn
101105
tokenOut, //tokenOut
102106
fee,
103107
address(uniswap),
104-
block.timestamp, //deadline
105108
amountIn,
106109
amountOutMin,
107110
0

foundry.toml

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ out = 'artifacts_forge'
3131
remappings = [
3232
'@uniswap/v3-core/contracts=lib/v3-core/contracts',
3333
'@uniswap/v3-periphery/contracts=lib/v3-periphery/contracts',
34+
'@uniswap/swap-router-contracts/contracts=lib/swap-router-contracts/contracts',
3435
'@chainlink/=lib/chainlink/',
3536
'@openzeppelin/contracts=lib/openzeppelin-contracts/contracts',
3637
'@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/',

lib/swap-router-contracts

Submodule swap-router-contracts added at c696aad

src/test/smart-wallet/token-paymaster/TokenPaymaster.t.sol

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { AccountFactory } from "contracts/prebuilts/account/non-upgradeable/Acco
1818
import { Account as SimpleAccount } from "contracts/prebuilts/account/non-upgradeable/Account.sol";
1919
import { TokenPaymaster, IERC20Metadata } from "contracts/prebuilts/account/token-paymaster/TokenPaymaster.sol";
2020
import { OracleHelper, IOracle } from "contracts/prebuilts/account/utils/OracleHelper.sol";
21-
import { UniswapHelper, ISwapRouter } from "contracts/prebuilts/account/utils/UniswapHelper.sol";
21+
import { UniswapHelper, IV3SwapRouter } from "contracts/prebuilts/account/utils/UniswapHelper.sol";
2222

2323
/// @dev This is a dummy contract to test contract interactions with Account.
2424
contract Number {
@@ -115,14 +115,15 @@ contract TokenPaymasterTest is BaseTest {
115115
UniswapHelper.UniswapHelperConfig memory uniswapHelperConfig = UniswapHelper.UniswapHelperConfig({
116116
minSwapAmount: 1,
117117
slippage: 5,
118-
uniswapPoolFee: 3
118+
uniswapPoolFee: 3,
119+
wethIsNativeAsset: false
119120
});
120121

121122
paymaster = new TokenPaymaster(
122123
IERC20Metadata(address(token)),
123124
entrypoint,
124125
weth,
125-
ISwapRouter(address(testUniswap)),
126+
IV3SwapRouter(address(testUniswap)),
126127
tokenPaymasterConfig,
127128
oracleHelperConfig,
128129
uniswapHelperConfig,

0 commit comments

Comments
 (0)