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

Token paymaster no uniswapper #12

Merged
merged 21 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ node_modules
/coverage
/coverage.json

/deploy.txt
deploy.txt

node_modules
.env

Expand Down
18 changes: 15 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
[submodule "lib/nexus"]
path = lib/nexus
url = https://github.com/bcnmy/nexus
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/account-abstraction"]
path = lib/account-abstraction
url = https://github.com/eth-infinitism/account-abstraction
[submodule "lib/nexus"]
path = lib/nexus
url = https://github.com/bcnmy/nexus
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "lib/v3-core"]
path = lib/v3-core
url = https://github.com/Uniswap/v3-core
[submodule "lib/v3-periphery"]
path = lib/v3-periphery
url = https://github.com/Uniswap/v3-periphery
11 changes: 7 additions & 4 deletions contracts/base/BasePaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ pragma solidity ^0.8.26;

import { SoladyOwnable } from "../utils/SoladyOwnable.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { IPaymaster } from "account-abstraction/contracts/interfaces/IPaymaster.sol";
import { IEntryPoint } from "account-abstraction/contracts/interfaces/IEntryPoint.sol";
import "account-abstraction/contracts/core/UserOperationLib.sol";
import { IPaymaster } from "@account-abstraction/contracts/interfaces/IPaymaster.sol";
import { IEntryPoint } from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import "@account-abstraction/contracts/core/UserOperationLib.sol";
/**
* Helper class for creating a paymaster.
* provides helper methods for staking.
Expand Down Expand Up @@ -163,7 +163,10 @@ abstract contract BasePaymaster is IPaymaster, SoladyOwnable {
require(msg.sender == address(entryPoint), "Sender not EntryPoint");
}

function isContract(address _addr) internal view returns (bool) {
/**
* Check if address is a contract
*/
function _isContract(address _addr) internal view returns (bool) {
uint256 size;
assembly ("memory-safe") {
size := extcodesize(_addr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract BiconomySponsorshipPaymasterErrors {
/**
* @notice Throws when invalid signature length in paymasterAndData
*/
error InvalidDynamicAdjustment();
error InvalidPriceMarkup();

/**
* @notice Throws when insufficient funds for paymasterid
Expand Down
78 changes: 78 additions & 0 deletions contracts/common/BiconomyTokenPaymasterErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.26;

contract BiconomyTokenPaymasterErrors {
/**
* @notice Throws when the verifiying signer address provided is address(0)
*/
error VerifyingSignerCanNotBeZero();
/**
* @notice Throws when the fee collector address provided is a deployed contract
*/
error VerifyingSignerCanNotBeContract();

/**
* @notice Throws when the fee collector address provided is address(0)
*/
error FeeCollectorCanNotBeZero();

/**
* @notice Throws when trying unaccountedGas is too high
*/
error UnaccountedGasTooHigh();

/**
* @notice Throws when trying to withdraw to address(0)
*/
error CanNotWithdrawToZeroAddress();

/**
* @notice Throws when trying to withdraw multiple tokens, but each token doesn't have a corresponding amount
*/
error TokensAndAmountsLengthMismatch();

/**
* @notice Throws when invalid signature length in paymasterAndData
*/
error InvalidPriceMarkup();

/**
* @notice Throws when each token doesnt have a corresponding oracle
*/
error TokensAndInfoLengthMismatch();

/**
* @notice Throws when invalid PaymasterMode specified in paymasterAndData
*/
error InvalidPaymasterMode();

/**
* @notice Throws when oracle returns invalid price
*/
error OraclePriceNotPositive();

/**
* @notice Throws when oracle price hasn't been updated for a duration of time the owner is comfortable with
*/
error OraclePriceExpired();

/**
* @notice Throws when token address to pay with is invalid
*/
error InvalidTokenAddress();

/**
* @notice Throws when user tries to pay with an unsupported token
*/
error TokenNotSupported();

/**
* @notice Throws when oracle decimals aren't equal to 8
*/
error InvalidOracleDecimals();

/**
* @notice Throws when external signer's signature has invalid length
*/
error InvalidSignatureLength();
}
49 changes: 43 additions & 6 deletions contracts/interfaces/IBiconomySponsorshipPaymaster.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,54 @@
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

interface IBiconomySponsorshipPaymaster {
event UnaccountedGasChanged(uint256 indexed oldValue, uint256 indexed newValue);
event FixedDynamicAdjustmentChanged(uint32 indexed oldValue, uint32 indexed newValue);
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { PackedUserOperation } from "@account-abstraction/contracts/core/UserOperationLib.sol";

interface IBiconomySponsorshipPaymaster{
event UnaccountedGasChanged(uint256 indexed oldValue, uint256 indexed newValue);
event FixedPriceMarkupChanged(uint256 indexed oldValue, uint256 indexed newValue);
event VerifyingSignerChanged(address indexed oldSigner, address indexed newSigner, address indexed actor);

event FeeCollectorChanged(address indexed oldFeeCollector, address indexed newFeeCollector, address indexed actor);
event GasDeposited(address indexed paymasterId, uint256 indexed value);
event GasWithdrawn(address indexed paymasterId, address indexed to, uint256 indexed value);
event GasBalanceDeducted(address indexed paymasterId, uint256 indexed charge, bytes32 indexed userOpHash);
event DynamicAdjustmentCollected(address indexed paymasterId, uint256 indexed dynamicAdjustment);
event PriceMarkupCollected(address indexed paymasterId, uint256 indexed priceMarkup);
event Received(address indexed sender, uint256 value);
event TokensWithdrawn(address indexed token, address indexed to, uint256 indexed amount, address actor);

function depositFor(address paymasterId) external payable;

function setSigner(address _newVerifyingSigner) external payable;

function setFeeCollector(address _newFeeCollector) external payable;

function setUnaccountedGas(uint256 value) external payable;

function withdrawERC20(IERC20 token, address target, uint256 amount) external;

function withdrawEth(address payable recipient, uint256 amount) external payable;

function getBalance(address paymasterId) external view returns (uint256 balance);

function getHash(
PackedUserOperation calldata userOp,
address paymasterId,
uint48 validUntil,
uint48 validAfter,
uint32 priceMarkup
)
external
view
returns (bytes32);

function parsePaymasterAndData(bytes calldata paymasterAndData)
external
pure
returns (
address paymasterId,
uint48 validUntil,
uint48 validAfter,
uint32 priceMarkup,
bytes calldata signature
);
}
52 changes: 52 additions & 0 deletions contracts/interfaces/IBiconomyTokenPaymaster.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import { IOracle } from "./oracles/IOracle.sol";

interface IBiconomyTokenPaymaster {
// Modes that paymaster can be used in
enum PaymasterMode {
EXTERNAL, // Price provided by external service. Authenticated using signature from verifyingSigner
INDEPENDENT // Price queried from oracle. No signature needed from external service.

}

// Struct for storing information about the token
struct TokenInfo {
IOracle oracle;
uint256 decimals;
}

event UpdatedUnaccountedGas(uint256 indexed oldValue, uint256 indexed newValue);
event UpdatedFixedPriceMarkup(uint256 indexed oldValue, uint256 indexed newValue);
event UpdatedVerifyingSigner(address indexed oldSigner, address indexed newSigner, address indexed actor);
event UpdatedFeeCollector(address indexed oldFeeCollector, address indexed newFeeCollector, address indexed actor);
event UpdatedPriceExpiryDuration(uint256 indexed oldValue, uint256 indexed newValue);
event TokensRefunded(
address indexed userOpSender, address indexed token, uint256 refundAmount, bytes32 indexed userOpHash
);
event PaidGasInTokens(
address indexed userOpSender,
address indexed token,
uint256 nativeCharge,
uint256 tokenCharge,
uint256 priceMarkup,
bytes32 indexed userOpHash
);
event Received(address indexed sender, uint256 value);
event TokensWithdrawn(address indexed token, address indexed to, uint256 indexed amount, address actor);
event UpdatedTokenDirectory(address indexed tokenAddress, IOracle indexed oracle, uint8 decimals);
event UpdatedNativeAssetOracle(IOracle indexed oldOracle, IOracle indexed newOracle);

function setSigner(address _newVerifyingSigner) external payable;

function setUnaccountedGas(uint256 value) external payable;

function setPriceMarkup(uint256 _newUnaccountedGas) external payable;

function setPriceExpiryDuration(uint256 _newPriceExpiryDuration) external payable;

function setNativeOracle(IOracle _oracle) external payable;

function updateTokenDirectory(address _tokenAddress, IOracle _oracle) external payable;
}
10 changes: 10 additions & 0 deletions contracts/interfaces/oracles/IOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IOracle {
function decimals() external view returns (uint8);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
50 changes: 50 additions & 0 deletions contracts/libraries/TokenPaymasterParserLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import { IBiconomyTokenPaymaster } from "../interfaces/IBiconomyTokenPaymaster.sol";
import "@account-abstraction/contracts/core/UserOperationLib.sol";

// A helper library to parse paymaster and data
library TokenPaymasterParserLib {
// Start offset of mode in PND
uint256 private constant PAYMASTER_MODE_OFFSET = UserOperationLib.PAYMASTER_DATA_OFFSET;

function parsePaymasterAndData(bytes calldata paymasterAndData)
external
pure
returns (IBiconomyTokenPaymaster.PaymasterMode mode, bytes memory modeSpecificData)
{
unchecked {
mode = IBiconomyTokenPaymaster.PaymasterMode(uint8(bytes1(paymasterAndData[PAYMASTER_MODE_OFFSET])));
modeSpecificData = paymasterAndData[PAYMASTER_MODE_OFFSET + 1:];
}
}

function parseExternalModeSpecificData(bytes calldata modeSpecificData)
external
pure
returns (
uint48 validUntil,
uint48 validAfter,
address tokenAddress,
uint128 tokenPrice,
uint32 externalPriceMarkup,
bytes memory signature
)
{
validUntil = uint48(bytes6(modeSpecificData[:6]));
validAfter = uint48(bytes6(modeSpecificData[6:12]));
tokenAddress = address(bytes20(modeSpecificData[12:32]));
tokenPrice = uint128(bytes16(modeSpecificData[32:48]));
externalPriceMarkup = uint32(bytes4(modeSpecificData[48:52]));
signature = modeSpecificData[52:];
}

function parseIndependentModeSpecificData(bytes calldata modeSpecificData)
external
pure
returns (address tokenAddress)
{
tokenAddress = address(bytes20(modeSpecificData[:20]));
}
}
7 changes: 2 additions & 5 deletions contracts/mocks/Imports.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,5 @@ pragma solidity ^0.8.26;

/* solhint-disable reason-string */

import "account-abstraction/contracts/core/EntryPoint.sol";
import "account-abstraction/contracts/core/EntryPointSimulations.sol";

import "@biconomy-devx/erc7579-msa/contracts/SmartAccount.sol";
import "@biconomy-devx/erc7579-msa/contracts/factory/AccountFactory.sol";
import "@account-abstraction/contracts/core/EntryPoint.sol";
import "@account-abstraction/contracts/core/EntryPointSimulations.sol";
Loading
Loading