Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TokenPaymaster] Support chains without WETH9 & Other Improvements #670

Merged
merged 7 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@
[submodule "lib/v3-core"]
path = lib/v3-core
url = https://github.com/uniswap/v3-core
[submodule "lib/swap-router-contracts"]
path = lib/swap-router-contracts
url = https://github.com/Uniswap/swap-router-contracts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
IERC20Metadata _token,
IEntryPoint _entryPoint,
IERC20 _wrappedNative,
ISwapRouter _uniswap,
IV3SwapRouter _uniswap,
TokenPaymasterConfig memory _tokenPaymasterConfig,
OracleHelperConfig memory _oracleHelperConfig,
UniswapHelperConfig memory _uniswapHelperConfig,
Expand Down Expand Up @@ -98,6 +98,10 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
_setUniswapHelperConfiguration(_uniswapHelperConfig);
}

function setOracleConfiguration(OracleHelperConfig memory _oracleHelperConfig) external onlyOwner {
_setOracleConfiguration(_oracleHelperConfig);
}

/// @notice Allows the contract owner to withdraw a specified amount of tokens from the contract.
/// @param to The address to transfer the tokens to.
/// @param amount The amount of tokens to transfer.
Expand Down Expand Up @@ -161,7 +165,8 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
unchecked {
uint256 priceMarkup = tokenPaymasterConfig.priceMarkup;
(uint256 preCharge, address userOpSender) = abi.decode(context, (uint256, address));
uint256 _cachedPrice = updateCachedPrice(false);
bool forceUpdate = (block.timestamp - cachedPriceTimestamp) > tokenPaymasterConfig.priceMaxAge;
uint256 _cachedPrice = updateCachedPrice(forceUpdate);
// note: as price is in native-asset-per-token and we want more tokens increasing it means dividing it by markup
uint256 cachedPriceWithMarkup = (_cachedPrice * PRICE_DENOMINATOR) / priceMarkup;
// Refund tokens based on actual gas cost
Expand Down
4 changes: 2 additions & 2 deletions contracts/prebuilts/account/utils/OracleHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract contract OracleHelper {
/// @notice The timestamp of a block when the cached price was updated
uint48 public cachedPriceTimestamp;

OracleHelperConfig private oracleHelperConfig;
OracleHelperConfig public oracleHelperConfig;

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

function _setOracleConfiguration(OracleHelperConfig memory _oracleHelperConfig) private {
function _setOracleConfiguration(OracleHelperConfig memory _oracleHelperConfig) internal {
oracleHelperConfig = _oracleHelperConfig;
require(_oracleHelperConfig.priceUpdateThreshold <= PRICE_DENOMINATOR, "TPM: update threshold too high");
tokenOracleDecimalPower = uint128(10 ** oracleHelperConfig.tokenOracle.decimals());
Expand Down
15 changes: 9 additions & 6 deletions contracts/prebuilts/account/utils/UniswapHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pragma solidity ^0.8.23;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

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

abstract contract UniswapHelper {
Expand All @@ -19,23 +19,24 @@ abstract contract UniswapHelper {
uint256 minSwapAmount;
uint24 uniswapPoolFee;
uint8 slippage;
bool wethIsNativeAsset;
}

/// @notice The Uniswap V3 SwapRouter contract
ISwapRouter public immutable uniswap;
IV3SwapRouter public immutable uniswap;

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

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

UniswapHelperConfig private uniswapHelperConfig;
UniswapHelperConfig public uniswapHelperConfig;

constructor(
IERC20Metadata _token,
IERC20 _wrappedNative,
ISwapRouter _uniswap,
IV3SwapRouter _uniswap,
UniswapHelperConfig memory _uniswapHelperConfig
) {
_token.approve(address(_uniswap), type(uint256).max);
Expand Down Expand Up @@ -85,6 +86,9 @@ abstract contract UniswapHelper {
}

function unwrapWeth(uint256 amount) internal {
if (uniswapHelperConfig.wethIsNativeAsset) {
return;
}
IPeripheryPayments(address(uniswap)).unwrapWETH9(amount, address(this));
}

Expand All @@ -96,12 +100,11 @@ abstract contract UniswapHelper {
uint256 amountOutMin,
uint24 fee
) internal returns (uint256 amountOut) {
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams(
IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter.ExactInputSingleParams(
tokenIn, //tokenIn
tokenOut, //tokenOut
fee,
address(uniswap),
block.timestamp, //deadline
amountIn,
amountOutMin,
0
Expand Down
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ out = 'artifacts_forge'
remappings = [
'@uniswap/v3-core/contracts=lib/v3-core/contracts',
'@uniswap/v3-periphery/contracts=lib/v3-periphery/contracts',
'@uniswap/swap-router-contracts/contracts=lib/swap-router-contracts/contracts',
'@chainlink/=lib/chainlink/',
'@openzeppelin/contracts=lib/openzeppelin-contracts/contracts',
'@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/',
Expand Down
1 change: 1 addition & 0 deletions lib/swap-router-contracts
Submodule swap-router-contracts added at c696aa
7 changes: 4 additions & 3 deletions src/test/smart-wallet/token-paymaster/TokenPaymaster.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { AccountFactory } from "contracts/prebuilts/account/non-upgradeable/Acco
import { Account as SimpleAccount } from "contracts/prebuilts/account/non-upgradeable/Account.sol";
import { TokenPaymaster, IERC20Metadata } from "contracts/prebuilts/account/token-paymaster/TokenPaymaster.sol";
import { OracleHelper, IOracle } from "contracts/prebuilts/account/utils/OracleHelper.sol";
import { UniswapHelper, ISwapRouter } from "contracts/prebuilts/account/utils/UniswapHelper.sol";
import { UniswapHelper, IV3SwapRouter } from "contracts/prebuilts/account/utils/UniswapHelper.sol";

/// @dev This is a dummy contract to test contract interactions with Account.
contract Number {
Expand Down Expand Up @@ -115,14 +115,15 @@ contract TokenPaymasterTest is BaseTest {
UniswapHelper.UniswapHelperConfig memory uniswapHelperConfig = UniswapHelper.UniswapHelperConfig({
minSwapAmount: 1,
slippage: 5,
uniswapPoolFee: 3
uniswapPoolFee: 3,
wethIsNativeAsset: false
});

paymaster = new TokenPaymaster(
IERC20Metadata(address(token)),
entrypoint,
weth,
ISwapRouter(address(testUniswap)),
IV3SwapRouter(address(testUniswap)),
tokenPaymasterConfig,
oracleHelperConfig,
uniswapHelperConfig,
Expand Down
Loading