diff --git a/contracts/interfaces/IBiconomyTokenPaymaster.sol b/contracts/interfaces/IBiconomyTokenPaymaster.sol index 365411e..9fc43e8 100644 --- a/contracts/interfaces/IBiconomyTokenPaymaster.sol +++ b/contracts/interfaces/IBiconomyTokenPaymaster.sol @@ -14,7 +14,8 @@ interface IBiconomyTokenPaymaster { // Struct for storing information about the token struct TokenInfo { IOracle oracle; - uint256 decimals; + uint32 priceMarkup; + uint256 priceExpiryDuration; } event UpdatedUnaccountedGas(uint256 indexed oldValue, uint256 indexed newValue); @@ -46,11 +47,11 @@ interface IBiconomyTokenPaymaster { function setUnaccountedGas(uint256 value) external payable; - function setPriceMarkup(uint32 newPriceMarkup) external payable; + function setPriceMarkupForToken(address tokenAddress, uint32 newPriceMarkup) external payable; - function setPriceExpiryDuration(uint256 newPriceExpiryDuration) external payable; + function setPriceExpiryDurationForToken(address tokenAddress, uint256 newPriceExpiryDuration) external payable; function setNativeAssetToUsdOracle(IOracle oracle) external payable; - function addToTokenDirectory(address tokenAddress, IOracle oracle) external payable; + function addToTokenDirectory(address tokenAddress, TokenInfo memory tokenInfo) external payable; } diff --git a/contracts/token/BiconomyTokenPaymaster.sol b/contracts/token/BiconomyTokenPaymaster.sol index ee0f498..81c0820 100644 --- a/contracts/token/BiconomyTokenPaymaster.sol +++ b/contracts/token/BiconomyTokenPaymaster.sol @@ -50,31 +50,33 @@ contract BiconomyTokenPaymaster is // State variables address public verifyingSigner; // entity used to provide external token price and markup uint256 public unaccountedGas; - uint32 public independentPriceMarkup; // price markup used for independent mode - uint256 public priceExpiryDuration; // oracle price expiry duration IOracle public nativeAssetToUsdOracle; // ETH -> USD price oracle mapping(address => TokenInfo) public independentTokenDirectory; // mapping of token address => info for tokens - // supported in // independent mode - uint256 private constant _UNACCOUNTED_GAS_LIMIT = 200_000; // Limit for unaccounted gas cost uint32 private constant _PRICE_DENOMINATOR = 1e6; // Denominator used when calculating cost with price markup uint32 private constant _MAX_PRICE_MARKUP = 2e6; // 100% premium on price (2e6/PRICE_DENOMINATOR) - uint256 private immutable _NATIVE_TOKEN_DECIMALS; + uint256 private immutable _NATIVE_TOKEN_DECIMALS; // gas savings + uint256 private immutable _NATIVE_ASSET_PRICE_EXPIRY_DURATION; // gas savings + + /** + * @dev markup and expiry duration are provided for each token. + * Price expiry duration should be set to the heartbeat value of the token. + * Additionally, priceMarkup must be higher than Chainlink’s deviation threshold value. + * More: https://docs.chain.link/architecture-overview/architecture-decentralized-model + */ constructor( address owner, address verifyingSignerArg, IEntryPoint entryPoint, uint256 unaccountedGasArg, - uint32 independentPriceMarkupArg, // price markup used for independent mode - uint256 priceExpiryDurationArg, uint256 nativeAssetDecimalsArg, IOracle nativeAssetToUsdOracleArg, + uint256 nativeAssetPriceExpiryDurationArg, IV3SwapRouter uniswapRouterArg, address wrappedNativeArg, - address[] memory independentTokensArg, // Array of token addresses supported by the paymaster in independent - // mode - IOracle[] memory oraclesArg, // Array of corresponding oracle addresses for independently supported tokens + address[] memory independentTokensArg, // Array of tokens supported in independent mode + TokenInfo[] memory tokenInfosArg, // Array of corresponding tokenInfo objects address[] memory swappableTokens, // Array of tokens that you want swappable by the uniswapper uint24[] memory swappableTokenPoolFeeTiers // Array of uniswap pool fee tiers for each swappable token ) @@ -82,6 +84,8 @@ contract BiconomyTokenPaymaster is Uniswapper(uniswapRouterArg, wrappedNativeArg, swappableTokens, swappableTokenPoolFeeTiers) { _NATIVE_TOKEN_DECIMALS = nativeAssetDecimalsArg; + _NATIVE_ASSET_PRICE_EXPIRY_DURATION = nativeAssetPriceExpiryDurationArg; + if (_isContract(verifyingSignerArg)) { revert VerifyingSignerCanNotBeContract(); } @@ -91,38 +95,25 @@ contract BiconomyTokenPaymaster is if (unaccountedGasArg > _UNACCOUNTED_GAS_LIMIT) { revert UnaccountedGasTooHigh(); } - if (independentPriceMarkupArg > _MAX_PRICE_MARKUP || independentPriceMarkupArg < _PRICE_DENOMINATOR) { - // Not between 0% and 100% markup - revert InvalidPriceMarkup(); - } - if (independentTokensArg.length != oraclesArg.length) { + + if (independentTokensArg.length != tokenInfosArg.length) { revert TokensAndInfoLengthMismatch(); } if (nativeAssetToUsdOracleArg.decimals() != 8) { // ETH -> USD will always have 8 decimals for Chainlink and TWAP revert InvalidOracleDecimals(); } - if (block.timestamp < priceExpiryDurationArg) { - revert InvalidPriceExpiryDuration(); - } // Set state variables assembly ("memory-safe") { sstore(verifyingSigner.slot, verifyingSignerArg) sstore(unaccountedGas.slot, unaccountedGasArg) - sstore(independentPriceMarkup.slot, independentPriceMarkupArg) - sstore(priceExpiryDuration.slot, priceExpiryDurationArg) sstore(nativeAssetToUsdOracle.slot, nativeAssetToUsdOracleArg) } - // Populate the tokenToOracle mapping for (uint256 i = 0; i < independentTokensArg.length; i++) { - if (oraclesArg[i].decimals() != 8) { - // Token -> USD will always have 8 decimals - revert InvalidOracleDecimals(); - } - independentTokenDirectory[independentTokensArg[i]] = - TokenInfo(oraclesArg[i], 10 ** IERC20Metadata(independentTokensArg[i]).decimals()); + _validateTokenInfo(tokenInfosArg[i]); + independentTokenDirectory[independentTokensArg[i]] = tokenInfosArg[i]; } } @@ -253,15 +244,13 @@ contract BiconomyTokenPaymaster is * @param newIndependentPriceMarkup The new value to be set as the price markup * @notice only to be called by the owner of the contract. */ - function setPriceMarkup(uint32 newIndependentPriceMarkup) external payable onlyOwner { + function setPriceMarkupForToken(address tokenAddress, uint32 newIndependentPriceMarkup) external payable onlyOwner { if (newIndependentPriceMarkup > _MAX_PRICE_MARKUP || newIndependentPriceMarkup < _PRICE_DENOMINATOR) { // Not between 0% and 100% markup revert InvalidPriceMarkup(); } - uint32 oldIndependentPriceMarkup = independentPriceMarkup; - assembly ("memory-safe") { - sstore(independentPriceMarkup.slot, newIndependentPriceMarkup) - } + uint32 oldIndependentPriceMarkup = independentTokenDirectory[tokenAddress].priceMarkup; + independentTokenDirectory[tokenAddress].priceMarkup = newIndependentPriceMarkup; emit UpdatedFixedPriceMarkup(oldIndependentPriceMarkup, newIndependentPriceMarkup); } @@ -270,12 +259,10 @@ contract BiconomyTokenPaymaster is * @param newPriceExpiryDuration The new value to be set as the price expiry duration * @notice only to be called by the owner of the contract. */ - function setPriceExpiryDuration(uint256 newPriceExpiryDuration) external payable onlyOwner { + function setPriceExpiryDurationForToken(address tokenAddress, uint256 newPriceExpiryDuration) external payable onlyOwner { if(block.timestamp < newPriceExpiryDuration) revert InvalidPriceExpiryDuration(); - uint256 oldPriceExpiryDuration = priceExpiryDuration; - assembly ("memory-safe") { - sstore(priceExpiryDuration.slot, newPriceExpiryDuration) - } + uint256 oldPriceExpiryDuration = independentTokenDirectory[tokenAddress].priceExpiryDuration; + independentTokenDirectory[tokenAddress].priceExpiryDuration = newPriceExpiryDuration; emit UpdatedPriceExpiryDuration(oldPriceExpiryDuration, newPriceExpiryDuration); } @@ -301,19 +288,15 @@ contract BiconomyTokenPaymaster is /** * @dev Set or update a TokenInfo entry in the independentTokenDirectory mapping. * @param tokenAddress The token address to add or update in directory - * @param oracle The oracle to use for the specified token + * @param tokenInfo The TokenInfo struct to add or update * @notice only to be called by the owner of the contract. */ - function addToTokenDirectory(address tokenAddress, IOracle oracle) external payable onlyOwner { - if (oracle.decimals() != 8) { - // Token -> USD will always have 8 decimals - revert InvalidOracleDecimals(); - } + function addToTokenDirectory(address tokenAddress, TokenInfo memory tokenInfo) external payable onlyOwner { + _validateTokenInfo(tokenInfo); - uint8 decimals = IERC20Metadata(tokenAddress).decimals(); - independentTokenDirectory[tokenAddress] = TokenInfo(oracle, 10 ** decimals); + independentTokenDirectory[tokenAddress] = tokenInfo; - emit AddedToTokenDirectory(tokenAddress, oracle, decimals); + emit AddedToTokenDirectory(tokenAddress, tokenInfo.oracle, IERC20Metadata(tokenAddress).decimals()); } /** @@ -323,7 +306,7 @@ contract BiconomyTokenPaymaster is */ function removeFromTokenDirectory(address tokenAddress) external payable onlyOwner { delete independentTokenDirectory[tokenAddress]; - emit RemovedFromTokenDirectory(tokenAddress ); + emit RemovedFromTokenDirectory(tokenAddress); } /** @@ -456,6 +439,24 @@ contract BiconomyTokenPaymaster is return independentTokenDirectory[tokenAddress].oracle != IOracle(address(0)); } + /** + * @dev Get the price markup for a token + * @param tokenAddress The address of the token to get the price markup of + * @return priceMarkup The price markup for the token + */ + function independentPriceMarkup(address tokenAddress) public view returns (uint32) { + return independentTokenDirectory[tokenAddress].priceMarkup; + } + + /** + * @dev Get the price expiry duration for a token + * @param tokenAddress The address of the token to get the price expiry duration of + * @return priceExpiryDuration The price expiry duration for the token + */ + function independentPriceExpiryDuration(address tokenAddress) public view returns (uint256) { + return independentTokenDirectory[tokenAddress].priceExpiryDuration; + } + /** * @dev Validate a user operation. * This method is abstract in BasePaymaster and must be implemented in derived contracts. @@ -555,11 +556,12 @@ contract BiconomyTokenPaymaster is revert TokenNotSupported(); } uint256 tokenAmount; + uint32 priceMarkup = independentTokenDirectory[tokenAddress].priceMarkup; { // Calculate token amount to precharge uint256 maxFeePerGas = UserOperationLib.unpackMaxFeePerGas(userOp); - tokenAmount = ((maxCost + maxPenalty + (unaccountedGas * maxFeePerGas)) * independentPriceMarkup * tokenPrice) + tokenAmount = ((maxCost + maxPenalty + (unaccountedGas * maxFeePerGas)) * priceMarkup * tokenPrice) / (_NATIVE_TOKEN_DECIMALS * _PRICE_DENOMINATOR); } @@ -570,9 +572,9 @@ contract BiconomyTokenPaymaster is abi.encode( userOp.sender, tokenAddress, - tokenAmount-((maxPenalty*tokenPrice*independentPriceMarkup)/(_NATIVE_TOKEN_DECIMALS*_PRICE_DENOMINATOR)), + tokenAmount-((maxPenalty*tokenPrice*priceMarkup)/(_NATIVE_TOKEN_DECIMALS*_PRICE_DENOMINATOR)), tokenPrice, - independentPriceMarkup, + priceMarkup, userOpHash ); validationData = 0; // Validation success and price is valid indefinetly @@ -621,6 +623,18 @@ contract BiconomyTokenPaymaster is ); } + function _validateTokenInfo(TokenInfo memory tokenInfo) internal view { + if (tokenInfo.oracle.decimals() != 8) { + revert InvalidOracleDecimals(); + } + if (tokenInfo.priceMarkup > _MAX_PRICE_MARKUP || tokenInfo.priceMarkup < _PRICE_DENOMINATOR) { + revert InvalidPriceMarkup(); + } + if (block.timestamp < tokenInfo.priceExpiryDuration) { + revert InvalidPriceExpiryDuration(); + } + } + /// @notice Fetches the latest token price. /// @return price The latest token price fetched from the oracles. function _getPrice(address tokenAddress) internal view returns (uint256 price) { @@ -633,11 +647,11 @@ contract BiconomyTokenPaymaster is } // Calculate price by using token and native oracle - uint256 tokenPrice = _fetchPrice(tokenInfo.oracle); - uint256 nativeAssetPrice = _fetchPrice(nativeAssetToUsdOracle); + uint256 tokenPrice = _fetchPrice(tokenInfo.oracle, tokenInfo.priceExpiryDuration); + uint256 nativeAssetPrice = _fetchPrice(nativeAssetToUsdOracle, _NATIVE_ASSET_PRICE_EXPIRY_DURATION); // Adjust to token decimals - price = (nativeAssetPrice * tokenInfo.decimals) / tokenPrice; + price = (nativeAssetPrice * 10**IERC20Metadata(tokenAddress).decimals()) / tokenPrice; } /// @notice Fetches the latest price from the given oracle. @@ -645,7 +659,7 @@ contract BiconomyTokenPaymaster is /// @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 (uint256 price) { + function _fetchPrice(IOracle oracle, uint256 priceExpiryDuration) internal view returns (uint256 price) { (, int256 answer,, uint256 updatedAt,) = oracle.latestRoundData(); if (answer <= 0) { revert OraclePriceNotPositive(); diff --git a/test/base/TestBase.sol b/test/base/TestBase.sol index 414be2d..efe7333 100644 --- a/test/base/TestBase.sol +++ b/test/base/TestBase.sol @@ -20,6 +20,7 @@ import { MockToken } from "@nexus/contracts/mocks/MockToken.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { BiconomySponsorshipPaymaster } from "../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; +import { IBiconomyTokenPaymaster } from "../../contracts/interfaces/IBiconomyTokenPaymaster.sol"; import { BiconomyTokenPaymaster, @@ -499,9 +500,9 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { return array; } - function _toSingletonArray(IOracle oracle) internal pure returns (IOracle[] memory) { - IOracle[] memory array = new IOracle[](1); - array[0] = oracle; + function _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo memory tokenInfo) internal pure returns (IBiconomyTokenPaymaster.TokenInfo[] memory) { + IBiconomyTokenPaymaster.TokenInfo[] memory array = new IBiconomyTokenPaymaster.TokenInfo[](1); + array[0] = tokenInfo; return array; } } \ No newline at end of file diff --git a/test/unit/concrete/TestTokenPaymaster.Base.t.sol b/test/unit/concrete/TestTokenPaymaster.Base.t.sol index 54a8c4f..e5e6347 100644 --- a/test/unit/concrete/TestTokenPaymaster.Base.t.sol +++ b/test/unit/concrete/TestTokenPaymaster.Base.t.sol @@ -8,6 +8,7 @@ import { BiconomyTokenPaymasterErrors, IOracle } from "../../../contracts/token/BiconomyTokenPaymaster.sol"; +import { IBiconomyTokenPaymaster } from "../../../contracts/interfaces/IBiconomyTokenPaymaster.sol"; import { MockOracle } from "../../mocks/MockOracle.sol"; import { MockToken } from "@nexus/contracts/mocks/MockToken.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -38,14 +39,13 @@ contract TestTokenPaymasterBase is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 50000, // unaccounted gas - 1e6, // price markup (for independent mode) - 1 days, // price expiry duration - 1e18, // native token decimals + 1e18, // native asset decimals nativeOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(usdc)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), _toSingletonArray(address(usdc)), _toSingletonArray(uint24(500)) // from here: https://basescan.org/address/0xd0b53D9277642d899DF5C87A3966A349A798F224#readContract ); @@ -58,14 +58,13 @@ contract TestTokenPaymasterBase is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 50000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration 1e18, // native token decimals nativeOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(usdc)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), _toSingletonArray(address(usdc)), _toSingletonArray(uint24(500)) // from here: https://basescan.org/address/0xd0b53D9277642d899DF5C87A3966A349A798F224#readContract ); @@ -75,7 +74,8 @@ contract TestTokenPaymasterBase is TestBase { assertEq(testArtifact.verifyingSigner(), PAYMASTER_SIGNER.addr); assertEq(address(testArtifact.nativeAssetToUsdOracle()), address(nativeOracle)); assertEq(testArtifact.unaccountedGas(), 50000); - assertEq(testArtifact.independentPriceMarkup(), 1e6); + assertEq(testArtifact.independentPriceMarkup(address(usdc)), 1e6); + assertEq(testArtifact.independentPriceExpiryDuration(address(usdc)), 1 days); } function test_BaseFork_Success_TokenPaymaster_IndependentMode_WithoutPremium() external { diff --git a/test/unit/concrete/TestTokenPaymaster.t.sol b/test/unit/concrete/TestTokenPaymaster.t.sol index c787c03..44a8140 100644 --- a/test/unit/concrete/TestTokenPaymaster.t.sol +++ b/test/unit/concrete/TestTokenPaymaster.t.sol @@ -8,6 +8,7 @@ import { BiconomyTokenPaymasterErrors, IOracle } from "../../../contracts/token/BiconomyTokenPaymaster.sol"; +import { IBiconomyTokenPaymaster } from "../../../contracts/interfaces/IBiconomyTokenPaymaster.sol"; import { MockOracle } from "../../mocks/MockOracle.sol"; import { MockToken } from "@nexus/contracts/mocks/MockToken.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -41,14 +42,13 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 50000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration - 1e18, // native token decimals + 1e18, // native asset decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -61,14 +61,13 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 5000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration 1e18, // native token decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -78,7 +77,8 @@ contract TestTokenPaymaster is TestBase { assertEq(testArtifact.verifyingSigner(), PAYMASTER_SIGNER.addr); assertEq(address(testArtifact.nativeAssetToUsdOracle()), address(nativeAssetToUsdOracle)); assertEq(testArtifact.unaccountedGas(), 5000); - assertEq(testArtifact.independentPriceMarkup(), 1e6); + assertEq(testArtifact.independentPriceMarkup(address(testToken)), 1e6); + assertEq(testArtifact.independentPriceExpiryDuration(address(testToken)), 1 days); } function test_RevertIf_DeployWithSignerSetToZero() external { @@ -88,15 +88,14 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_OWNER.addr, address(0), ENTRYPOINT, - 5000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration + 5000, // unaccounted gas 1e18, // native token decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -110,14 +109,13 @@ contract TestTokenPaymaster is TestBase { ENTRYPOINT_ADDRESS, ENTRYPOINT, 5000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration 1e18, // native token decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -130,14 +128,13 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 500_001, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration 1e18, // native token decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -150,14 +147,13 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 5000, // unaccounted gas - 2e6 + 1, // price markup - 1 days, // price expiry duration 1e18, // native token decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 2e6 + 1, 1 days)), new address[](0), new uint24[](0) ); @@ -224,14 +220,15 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 5000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration + //1e6, // price markup + //1 days, // price expiry duration 1e18, // native token decimals invalidOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(tokenOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(tokenOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -245,14 +242,13 @@ contract TestTokenPaymaster is TestBase { PAYMASTER_SIGNER.addr, ENTRYPOINT, 50_000, // unaccounted gas - 1e6, // price markup - 1 days, // price expiry duration 1e18, // native token decimals nativeAssetToUsdOracle, + 1 days, // native asset price expiry duration swapRouter, WRAPPED_NATIVE_ADDRESS, _toSingletonArray(address(testToken)), - _toSingletonArray(IOracle(address(invalidOracle))), + _toSingletonArray(IBiconomyTokenPaymaster.TokenInfo(IOracle(address(invalidOracle)), 1e6, 1 days)), new address[](0), new uint24[](0) ); @@ -346,7 +342,7 @@ contract TestTokenPaymaster is TestBase { // Test setting a high price markup function test_SetPriceMarkupTooHigh() external prankModifier(PAYMASTER_OWNER.addr) { vm.expectRevert(BiconomyTokenPaymasterErrors.InvalidPriceMarkup.selector); - tokenPaymaster.setPriceMarkup(2e6 + 1); // Setting too high + tokenPaymaster.setPriceMarkupForToken(address(testToken), 2e6 + 1); // Setting too high } // Test invalid signature in external mode @@ -504,13 +500,10 @@ contract TestTokenPaymaster is TestBase { PackedUserOperation[] memory ops = new PackedUserOperation[](1); ops[0] = userOp; - vm.expectEmit(true, true, false, false, address(tokenPaymaster)); emit IBiconomyTokenPaymaster.TokensRefunded(address(ALICE_ACCOUNT), address(testToken), 0, bytes32(0)); - vm.expectEmit(true, true, false, false, address(tokenPaymaster)); emit IBiconomyTokenPaymaster.PaidGasInTokens(address(ALICE_ACCOUNT), address(testToken), 0, 0, 1e6, 0, bytes32(0)); - startPrank(BUNDLER.addr); uint256 gasValue = gasleft(); ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr));