Skip to content

Commit

Permalink
Merge pull request #1 from bcnmy/feat/paymaster-foundry-tests
Browse files Browse the repository at this point in the history
Feat/paymaster foundry tests
  • Loading branch information
livingrockrises authored Jul 11, 2024
2 parents a921986 + 358aeb1 commit 036840b
Show file tree
Hide file tree
Showing 32 changed files with 2,386 additions and 1,227 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[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
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", "^0.8.24"],
"compiler-version": ["error", "^0.8.26"],
"func-visibility": ["warn", { "ignoreConstructors": true }],
"reentrancy": "error",
"state-visibility": "error",
Expand Down
166 changes: 94 additions & 72 deletions contracts/base/BasePaymaster.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

/* solhint-disable reason-string */

Expand All @@ -13,6 +13,7 @@ import "account-abstraction/contracts/core/UserOperationLib.sol";
* provides helper methods for staking.
* Validates that the postOp is called only by the entryPoint.
*/

abstract contract BasePaymaster is IPaymaster, SoladyOwnable {
IEntryPoint public immutable entryPoint;

Expand All @@ -25,22 +26,92 @@ abstract contract BasePaymaster is IPaymaster, SoladyOwnable {
entryPoint = _entryPoint;
}

//sanity check: make sure this EntryPoint was compiled against the same
// IEntryPoint of this paymaster
function _validateEntryPointInterface(IEntryPoint _entryPoint) internal virtual {
require(IERC165(address(_entryPoint)).supportsInterface(type(IEntryPoint).interfaceId), "IEntryPoint interface mismatch");
/**
* Add stake for this paymaster.
* This method can also carry eth value to add to the current stake.
* @param unstakeDelaySec - The unstake delay for this paymaster. Can only be increased.
*/
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
entryPoint.addStake{ value: msg.value }(unstakeDelaySec);
}

/**
* Unlock the stake, in order to withdraw it.
* The paymaster can't serve requests once unlocked, until it calls addStake again
*/
function unlockStake() external onlyOwner {
entryPoint.unlockStake();
}

/**
* Withdraw the entire paymaster's stake.
* stake must be unlocked first (and then wait for the unstakeDelay to be over)
* @param withdrawAddress - The address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external onlyOwner {
entryPoint.withdrawStake(withdrawAddress);
}

/// @inheritdoc IPaymaster
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
)
external
override
{
_requireFromEntryPoint();
_postOp(mode, context, actualGasCost, actualUserOpFeePerGas);
}

/// @inheritdoc IPaymaster
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external override returns (bytes memory context, uint256 validationData) {
)
external
override
returns (bytes memory context, uint256 validationData)
{
_requireFromEntryPoint();
return _validatePaymasterUserOp(userOp, userOpHash, maxCost);
}

/**
* Add a deposit for this paymaster, used for paying for transaction fees.
*/
function deposit() external payable virtual {
entryPoint.depositTo{ value: msg.value }(address(this));
}

/**
* Withdraw value from the deposit.
* @param withdrawAddress - Target to send to.
* @param amount - Amount to withdraw.
*/
function withdrawTo(address payable withdrawAddress, uint256 amount) external virtual onlyOwner {
entryPoint.withdrawTo(withdrawAddress, amount);
}

/**
* Return current paymaster's deposit on the entryPoint.
*/
function getDeposit() public view returns (uint256) {
return entryPoint.balanceOf(address(this));
}

//sanity check: make sure this EntryPoint was compiled against the same
// IEntryPoint of this paymaster
function _validateEntryPointInterface(IEntryPoint _entryPoint) internal virtual {
require(
IERC165(address(_entryPoint)).supportsInterface(type(IEntryPoint).interfaceId),
"IEntryPoint interface mismatch"
);
}

/**
* Validate a user operation.
* @param userOp - The user operation.
Expand All @@ -51,18 +122,10 @@ abstract contract BasePaymaster is IPaymaster, SoladyOwnable {
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal virtual returns (bytes memory context, uint256 validationData);

/// @inheritdoc IPaymaster
function postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) external override {
_requireFromEntryPoint();
_postOp(mode, context, actualGasCost, actualUserOpFeePerGas);
}
)
internal
virtual
returns (bytes memory context, uint256 validationData);

/**
* Post-operation handler.
Expand All @@ -84,68 +147,27 @@ abstract contract BasePaymaster is IPaymaster, SoladyOwnable {
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) internal virtual {
)
internal
virtual
{
(mode, context, actualGasCost, actualUserOpFeePerGas); // unused params
// subclass must override this method if validatePaymasterUserOp returns a context
revert("must override");
}

/**
* Add a deposit for this paymaster, used for paying for transaction fees.
*/
function deposit() public virtual payable {
entryPoint.depositTo{value: msg.value}(address(this));
}

/**
* Withdraw value from the deposit.
* @param withdrawAddress - Target to send to.
* @param amount - Amount to withdraw.
*/
function withdrawTo(
address payable withdrawAddress,
uint256 amount
) public virtual onlyOwner {
entryPoint.withdrawTo(withdrawAddress, amount);
}

/**
* Add stake for this paymaster.
* This method can also carry eth value to add to the current stake.
* @param unstakeDelaySec - The unstake delay for this paymaster. Can only be increased.
*/
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
entryPoint.addStake{value: msg.value}(unstakeDelaySec);
}

/**
* Return current paymaster's deposit on the entryPoint.
*/
function getDeposit() public view returns (uint256) {
return entryPoint.balanceOf(address(this));
}

/**
* Unlock the stake, in order to withdraw it.
* The paymaster can't serve requests once unlocked, until it calls addStake again
*/
function unlockStake() external onlyOwner {
entryPoint.unlockStake();
}

/**
* Withdraw the entire paymaster's stake.
* stake must be unlocked first (and then wait for the unstakeDelay to be over)
* @param withdrawAddress - The address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external onlyOwner {
entryPoint.withdrawStake(withdrawAddress);
}

/**
* Validate the call is made from a valid entrypoint
*/
function _requireFromEntryPoint() internal virtual {
require(msg.sender == address(entryPoint), "Sender not EntryPoint");
}
}

function isContract(address _addr) internal view returns (bool) {
uint256 size;
assembly ("memory-safe") {
size := extcodesize(_addr)
}
return size > 0;
}
}
49 changes: 41 additions & 8 deletions contracts/common/Errors.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

contract BiconomySponsorshipPaymasterErrors {

/**
* @notice Throws when the paymaster address provided is address(0)
*/
error PaymasterIdCannotBeZero();
error PaymasterIdCanNotBeZero();

/**
* @notice Throws when the 0 has been provided as deposit
Expand All @@ -16,26 +15,60 @@ contract BiconomySponsorshipPaymasterErrors {
/**
* @notice Throws when the verifiying signer address provided is address(0)
*/
error VerifyingSignerCannotBeZero();
error VerifyingSignerCanNotBeZero();

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

/**
* @notice Throws when the fee collector address provided is a deployed contract
*/
error FeeCollectorCannotBeContract();
error FeeCollectorCanNotBeContract();

/**
* @notice Throws when the fee collector address provided is a deployed contract
*/
error VerifyingSignerCannotBeContract();
error VerifyingSignerCanNotBeContract();

/**
* @notice Throws when ETH withdrawal fails
*/
error WithdrawalFailed();

/**
* @notice Throws when insufficient funds to withdraw
*/
error InsufficientFundsInGasTank();

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

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

/**
* @notice Throws when insufficient funds for paymasterid
*/
error InsufficientFundsForPaymasterId();

/**
* @notice Throws when calling deposit()
*/
error UseDepositForInstead();

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

}
/**
* @notice Throws when trying unaccountedGas is too high
*/
error UnaccountedGasTooHigh();
}
24 changes: 11 additions & 13 deletions contracts/interfaces/IBiconomySponsorshipPaymaster.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

interface IBiconomySponsorshipPaymaster {
event PostopCostChanged(uint256 indexed _oldValue, uint256 indexed _newValue);
event FixedPriceMarkupChanged(uint32 indexed _oldValue, uint32 indexed _newValue);
event UnaccountedGasChanged(uint256 indexed oldValue, uint256 indexed newValue);
event FixedDynamicAdjustmentChanged(uint32 indexed oldValue, uint32 indexed newValue);

event VerifyingSignerChanged(address indexed _oldSigner, address indexed _newSigner, address indexed _actor);
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 PremiumCollected(address indexed _paymasterId, uint256 indexed _premium);
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 Received(address indexed sender, uint256 value);
event TokensWithdrawn(address indexed _token, address indexed _to, uint256 indexed _amount, address actor);
}
event TokensWithdrawn(address indexed token, address indexed to, uint256 indexed amount, address actor);
}
3 changes: 1 addition & 2 deletions contracts/mocks/Imports.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

/* solhint-disable reason-string */

Expand All @@ -8,4 +8,3 @@ import "account-abstraction/contracts/core/EntryPointSimulations.sol";

import "@biconomy-devx/erc7579-msa/contracts/SmartAccount.sol";
import "@biconomy-devx/erc7579-msa/contracts/factory/AccountFactory.sol";

4 changes: 2 additions & 2 deletions contracts/mocks/MockValidator.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pragma solidity ^0.8.24;
pragma solidity ^0.8.26;

import "@biconomy-devx/erc7579-msa/test/foundry/mocks/MockValidator.sol";
import "@biconomy-devx/erc7579-msa/test/foundry/mocks/MockValidator.sol";
Loading

0 comments on commit 036840b

Please sign in to comment.