-
Notifications
You must be signed in to change notification settings - Fork 3
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
Feat/token paymaster test refactor #34
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
ecd920a
init
livingrockrises b4250ea
update tests
livingrockrises f6a2c4c
dev notes+test updates
livingrockrises ef204df
setup base mainnet test
livingrockrises 8279e9b
add a test for independent miode
livingrockrises 5b28b10
refactor
livingrockrises f38aa22
feat:add test for swapping on base
livingrockrises 25016ac
refactor
livingrockrises f5b7433
refactor
livingrockrises 026d758
feat:refactor test+update swapper and paymaster code
livingrockrises 03cba2c
logs for failing test accounting
livingrockrises 7fc869d
more logs+fix tokenprice in base test
livingrockrises 0fc2d26
Update contracts/token/BiconomyTokenPaymaster.sol
livingrockrises File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ | |
import { ECDSA as ECDSA_solady } from "solady/utils/ECDSA.sol"; | ||
import "account-abstraction/core/Helpers.sol"; | ||
import "./swaps/Uniswapper.sol"; | ||
// Todo: marked for removal | ||
import "forge-std/console2.sol"; | ||
|
||
/** | ||
* @title BiconomyTokenPaymaster | ||
|
@@ -56,7 +58,8 @@ | |
// supported in // independent mode | ||
|
||
// PAYMASTER_ID_OFFSET | ||
uint256 private constant _UNACCOUNTED_GAS_LIMIT = 50_000; // Limit for unaccounted gas cost | ||
// Note: Temp | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it for testing purposes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, haven't gotten to right accounting yet. |
||
uint256 private constant _UNACCOUNTED_GAS_LIMIT = 200_000; // Limit for unaccounted gas cost | ||
uint256 private constant _PRICE_DENOMINATOR = 1e6; // Denominator used when calculating cost with price markup | ||
uint256 private constant _MAX_PRICE_MARKUP = 2e6; // 100% premium on price (2e6/PRICE_DENOMINATOR) | ||
|
||
|
@@ -123,6 +126,11 @@ | |
independentTokenDirectory[independentTokensArg[i]] = | ||
TokenInfo(oraclesArg[i], 10 ** IERC20Metadata(independentTokensArg[i]).decimals()); | ||
} | ||
// Approve swappable tokens for max amount | ||
uint256 length = swappableTokens.length; | ||
for (uint256 i; i < length; i++) { | ||
IERC20(swappableTokens[i]).approve(address(uniswapRouterArg), type(uint256).max); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -338,10 +346,12 @@ | |
{ | ||
// Swap tokens for WETH | ||
uint256 amountOut = _swapTokenToWeth(tokenAddress, tokenAmount, minEthAmountRecevied); | ||
// Unwrap WETH to ETH | ||
_unwrapWeth(amountOut); | ||
// Deposit ETH into EP | ||
entryPoint.depositTo{ value: amountOut }(address(this)); | ||
if(amountOut > 0) { | ||
// Unwrap WETH to ETH | ||
_unwrapWeth(amountOut); | ||
// Deposit ETH into EP | ||
entryPoint.depositTo{ value: amountOut }(address(this)); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -412,7 +422,7 @@ | |
* @param userOpHash The hash of the user operation. | ||
* @param maxCost The maximum cost of the user operation. | ||
*/ | ||
function _validatePaymasterUserOp( | ||
PackedUserOperation calldata userOp, | ||
bytes32 userOpHash, | ||
uint256 maxCost | ||
|
@@ -427,6 +437,14 @@ | |
revert InvalidPaymasterMode(); | ||
} | ||
|
||
// callGasLimit + paymasterPostOpGas | ||
uint256 maxPenalty = ( | ||
( | ||
uint128(uint256(userOp.accountGasLimits)) | ||
+ uint128(bytes16(userOp.paymasterAndData[_PAYMASTER_POSTOP_GAS_OFFSET:_PAYMASTER_DATA_OFFSET])) | ||
) * 10 * userOp.unpackMaxFeePerGas() | ||
) / 100; | ||
|
||
if (mode == PaymasterMode.EXTERNAL) { | ||
// Use the price and other params specified in modeSpecificData by the verifyingSigner | ||
// Useful for supporting tokens which don't have oracle support | ||
|
@@ -435,7 +453,8 @@ | |
uint48 validUntil, | ||
uint48 validAfter, | ||
address tokenAddress, | ||
uint128 tokenPrice, | ||
// Review if uint128 is enough | ||
uint128 tokenPrice, // NotE: what backend should pass is token/native * 10^token decimals | ||
uint32 externalPriceMarkup, | ||
bytes memory signature | ||
) = modeSpecificData.parseExternalModeSpecificData(); | ||
|
@@ -460,10 +479,12 @@ | |
revert InvalidPriceMarkup(); | ||
} | ||
|
||
|
||
uint256 tokenAmount; | ||
// Review | ||
{ | ||
uint256 maxFeePerGas = UserOperationLib.unpackMaxFeePerGas(userOp); | ||
tokenAmount = ((maxCost + (unaccountedGas) * maxFeePerGas) * externalPriceMarkup * tokenPrice) | ||
tokenAmount = ((maxCost + maxPenalty + (unaccountedGas * maxFeePerGas)) * externalPriceMarkup * tokenPrice) | ||
/ (1e18 * _PRICE_DENOMINATOR); | ||
} | ||
|
||
|
@@ -480,13 +501,14 @@ | |
|
||
// Get address for token used to pay | ||
address tokenAddress = modeSpecificData.parseIndependentModeSpecificData(); | ||
uint192 tokenPrice = _getPrice(tokenAddress); | ||
uint256 tokenPrice = _getPrice(tokenAddress); | ||
uint256 tokenAmount; | ||
|
||
// TODO: Account for penalties here | ||
{ | ||
// Calculate token amount to precharge | ||
uint256 maxFeePerGas = UserOperationLib.unpackMaxFeePerGas(userOp); | ||
tokenAmount = ((maxCost + (unaccountedGas) * maxFeePerGas) * independentPriceMarkup * tokenPrice) | ||
tokenAmount = ((maxCost + maxPenalty + (unaccountedGas * maxFeePerGas)) * independentPriceMarkup * tokenPrice) | ||
/ (1e18 * _PRICE_DENOMINATOR); | ||
} | ||
|
||
|
@@ -529,6 +551,12 @@ | |
uint256 actualTokenAmount = ( | ||
(actualGasCost + (unaccountedGas * actualUserOpFeePerGas)) * appliedPriceMarkup * tokenPrice | ||
) / (1e18 * _PRICE_DENOMINATOR); | ||
console2.log("tokenPrice", tokenPrice); | ||
console2.log("appliedPriceMarkup", appliedPriceMarkup); | ||
console2.log("actualGasCost", actualGasCost); | ||
console2.log("actualUserOpFeePerGas", actualUserOpFeePerGas); | ||
console2.log("actualTokenAmount", actualTokenAmount); | ||
console2.log("prechargedAmount", prechargedAmount); | ||
|
||
if (prechargedAmount > actualTokenAmount) { | ||
// If the user was overcharged, refund the excess tokens | ||
|
@@ -537,14 +565,15 @@ | |
emit TokensRefunded(userOpSender, tokenAddress, refundAmount, userOpHash); | ||
} | ||
|
||
// Todo: Review events and what we need to emit. | ||
emit PaidGasInTokens( | ||
userOpSender, tokenAddress, actualGasCost, actualTokenAmount, appliedPriceMarkup, userOpHash | ||
); | ||
} | ||
|
||
/// @notice Fetches the latest token price. | ||
/// @return price The latest token price fetched from the oracles. | ||
function _getPrice(address tokenAddress) internal view returns (uint192 price) { | ||
function _getPrice(address tokenAddress) internal view returns (uint256 price) { | ||
// Fetch token information from directory | ||
TokenInfo memory tokenInfo = independentTokenDirectory[tokenAddress]; | ||
|
||
|
@@ -556,15 +585,19 @@ | |
// Calculate price by using token and native oracle | ||
uint192 tokenPrice = _fetchPrice(tokenInfo.oracle); | ||
uint192 nativeAssetPrice = _fetchPrice(nativeAssetToUsdOracle); | ||
console2.log("tokenPrice oracle", tokenPrice); | ||
console2.log("nativeAssetPrice oracle", nativeAssetPrice); | ||
|
||
// Adjust to token decimals | ||
price = (nativeAssetPrice * uint192(tokenInfo.decimals)) / tokenPrice; | ||
price = (nativeAssetPrice * tokenInfo.decimals) / tokenPrice; | ||
console2.log("derived & used price", price); | ||
} | ||
|
||
/// @notice Fetches the latest price from the given oracle. | ||
/// @dev This function is used to get the latest price from the tokenOracle or nativeAssetToUsdOracle. | ||
/// @param oracle The oracle contract to fetch the price from. | ||
/// @return price The latest price fetched from the oracle. | ||
/// Note: We could do this using oracle aggregator, so we can also use Pyth. or Twap based oracle and just not chainlink. | ||
function _fetchPrice(IOracle oracle) internal view returns (uint192 price) { | ||
(, int256 answer,, uint256 updatedAt,) = oracle.latestRoundData(); | ||
if (answer <= 0) { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you want to remove it after audit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes I will