Skip to content

Commit

Permalink
feat: create CardPaymentProcessor v2 (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
ihoroleksiienko authored Dec 3, 2024
1 parent e353cc3 commit 79e98ef
Show file tree
Hide file tree
Showing 34 changed files with 22,095 additions and 0 deletions.
2,022 changes: 2,022 additions & 0 deletions .openzeppelin/unknown-2008.json

Large diffs are not rendered by default.

2,022 changes: 2,022 additions & 0 deletions .openzeppelin/unknown-2009.json

Large diffs are not rendered by default.

1,384 changes: 1,384 additions & 0 deletions contracts/CardPaymentProcessor.sol

Large diffs are not rendered by default.

51 changes: 51 additions & 0 deletions contracts/CardPaymentProcessorStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { ICardPaymentProcessorTypes } from "./interfaces/ICardPaymentProcessor.sol";
import { ICardPaymentCashbackTypes } from "./interfaces/ICardPaymentCashback.sol";

/// @title CardPaymentProcessor storage version 1
abstract contract CardPaymentProcessorStorageV1 is ICardPaymentProcessorTypes, ICardPaymentCashbackTypes {
/// @dev The address of the underlying token.
address internal _token;

/// @dev The account to transfer confirmed tokens to.
address internal _cashOutAccount;

/// @dev The mapping of a payment for a given payment ID.
mapping(bytes32 => Payment) internal _payments;

/// @dev The payment statistics.
PaymentStatistics internal _paymentStatistics;

/// @dev The address of the cashback treasury.
address internal _cashbackTreasury;

/// @dev The enable flag of the cashback operations for new payments. Does not affect the existing payments.
bool internal _cashbackEnabled;

/// @dev The default cashback rate for new payments in units of `CASHBACK_FACTOR`.
uint16 internal _cashbackRate;

/// @dev The mapping of an account cashback structure for a given account address.
mapping(address => AccountCashbackState) internal _accountCashbackStates;
}

/**
* @title CardPaymentProcessor storage
* @dev Contains storage variables of the {CardPaymentProcessor} contract.
*
* We are following Compound's approach of upgrading new contract implementations.
* See https://github.com/compound-finance/compound-protocol.
* When we need to add new storage variables, we create a new version of CardPaymentProcessorStorage
* e.g. CardPaymentProcessorStorage<versionNumber>, so finally it would look like
* "contract CardPaymentProcessorStorage is CardPaymentProcessorStorageV1, CardPaymentProcessorStorageV2".
*/
abstract contract CardPaymentProcessorStorage is CardPaymentProcessorStorageV1 {
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
*/
uint256[43] private __gap;
}
75 changes: 75 additions & 0 deletions contracts/base/AccessControlExtUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

/**
* @title AccessControlExtUpgradeable base contract
* @author CloudWalk Inc.
* @dev Extends the OpenZeppelin's {AccessControlUpgradeable} contract by adding the `grantRoleBatch` and
* `revokeRoleBatch` function.
*
* This contract is used through inheritance. It introduces the `grantRoleBatch` and `revokeRoleBatch` functions
* that is allowed to grant and revoke roles in batch.
*/
abstract contract AccessControlExtUpgradeable is AccessControlUpgradeable {
// ------------------ Initializers ---------------------------- //

/**
* @dev The internal initializer of the upgradable contract.
*
* See details https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable.
*/
function __AccessControlExt_init() internal onlyInitializing {
__Context_init_unchained();
__ERC165_init_unchained();
__AccessControl_init_unchained();

__AccessControlExt_init_unchained();
}

/**
* @dev The unchained internal initializer of the upgradable contract.
*
* See {AccessControlExtUpgradeable-__AccessControlExt_init}.
*/
function __AccessControlExt_init_unchained() internal onlyInitializing {}

// ------------------ Functions ------------------------------- //

/**
* @dev Grants `role` to `account` in batch.
*
* If `accounts` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event for each account.
*/
function grantRoleBatch(bytes32 role, address[] memory accounts) public virtual onlyRole(getRoleAdmin(role)) {
for (uint i = 0; i < accounts.length; i++) {
_grantRole(role, accounts[i]);
}
}

/**
* @dev Revokes `role` from `account` in batch.
*
* If `accounts` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event for each account.
*/
function revokeRoleBatch(bytes32 role, address[] memory accounts) public virtual onlyRole(getRoleAdmin(role)) {
for (uint i = 0; i < accounts.length; i++) {
_revokeRole(role, accounts[i]);
}
}
}
177 changes: 177 additions & 0 deletions contracts/base/BlocklistableUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { AccessControlExtUpgradeable } from "./AccessControlExtUpgradeable.sol";

/**
* @title BlocklistableUpgradeable base contract
* @author CloudWalk Inc.
* @dev Allows to blocklist and unblocklist accounts using the {BLOCKLISTER_ROLE} role.
*
* This contract is used through inheritance. It makes available the modifier `notBlocklisted`,
* which can be applied to functions to restrict their usage to not blocklisted accounts only.
*/
abstract contract BlocklistableUpgradeable is AccessControlExtUpgradeable {
/// @dev The role of the blocklister that is allowed to blocklist and unblocklist accounts.
bytes32 public constant BLOCKLISTER_ROLE = keccak256("BLOCKLISTER_ROLE");

/**
* @dev The first storage slot of the contract data.
*
* Calculated as:
* keccak256(abi.encode(uint256(keccak256("cloudwalk.storage.Blocklistable")) - 1)) & ~bytes32(uint256(0xff))
*/
bytes32 private constant BlocklistableStorageLocation =
0x9a5d41467ec00b9c4ff3b10f2ab1b7fef3c7f16bd8fba9cd308a28e3cd7ef400;

/**
* @dev The structure that contains all the data of the Blocklistable contract.
* @custom:storage-location erc7201:cloudwalk.storage.Blocklistable
*/
struct BlocklistableStorage {
mapping(address => bool) blocklisted; // Mapping of presence in the blocklist for a given address.
}

// ------------------ Events ---------------------------------- //

/// @dev Emitted when an account is blocklisted.
event Blocklisted(address indexed account);

/// @dev Emitted when an account is unblocklisted.
event UnBlocklisted(address indexed account);

/// @dev Emitted when an account is self blocklisted.
event SelfBlocklisted(address indexed account);

// ------------------ Errors ---------------------------------- //

/// @dev The account is blocklisted.
error BlocklistedAccount(address account);

// ------------------ Modifiers ------------------------------- //

/**
* @dev Throws if called by a blocklisted account.
* @param account The address to check for presence in the blocklist.
*/
modifier notBlocklisted(address account) {
if (_getBlocklistableStorage().blocklisted[account]) {
revert BlocklistedAccount(account);
}
_;
}

// ------------------ Initializers ---------------------------- //

/**
* @dev The internal initializer of the upgradable contract.
*
* See details https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable.
*/
function __Blocklistable_init(bytes32 blocklisterRoleAdmin) internal onlyInitializing {
__Context_init_unchained();
__ERC165_init_unchained();
__AccessControl_init_unchained();
__AccessControlExt_init_unchained();

__Blocklistable_init_unchained(blocklisterRoleAdmin);
}

/**
* @dev The unchained internal initializer of the upgradable contract.
*
* See {BlocklistableUpgradeable-__Blocklistable_init}.
*/
function __Blocklistable_init_unchained(bytes32 blocklisterRoleAdmin) internal onlyInitializing {
_setRoleAdmin(BLOCKLISTER_ROLE, blocklisterRoleAdmin);
}

// ------------------ Functions ------------------------------- //

/**
* @dev Adds an account to the blocklist.
*
* Requirements:
*
* - The caller must have the {BLOCKLISTER_ROLE} role.
*
* Emits a {Blocklisted} event.
*
* @param account The address to blocklist.
*/
function blocklist(address account) public onlyRole(BLOCKLISTER_ROLE) {
BlocklistableStorage storage s = _getBlocklistableStorage();
if (s.blocklisted[account]) {
return;
}

s.blocklisted[account] = true;

emit Blocklisted(account);
}

/**
* @dev Removes an account from the blocklist.
*
* Requirements:
*
* - The caller must have the {BLOCKLISTER_ROLE} role.
*
* Emits an {UnBlocklisted} event.
*
* @param account The address to remove from the blocklist.
*/
function unBlocklist(address account) public onlyRole(BLOCKLISTER_ROLE) {
BlocklistableStorage storage s = _getBlocklistableStorage();
if (!s.blocklisted[account]) {
return;
}

s.blocklisted[account] = false;

emit UnBlocklisted(account);
}

/**
* @dev Adds the message sender to the blocklist.
*
* Emits a {SelfBlocklisted} event.
* Emits a {Blocklisted} event.
*/
function selfBlocklist() public {
address sender = _msgSender();
BlocklistableStorage storage s = _getBlocklistableStorage();

if (s.blocklisted[sender]) {
return;
}

s.blocklisted[sender] = true;

emit SelfBlocklisted(sender);
emit Blocklisted(sender);
}

// ------------------ View functions -------------------------- //

/**
* @dev Checks if an account is blocklisted.
* @param account The address to check for presence in the blocklist.
* @return True if the account is present in the blocklist.
*/
function isBlocklisted(address account) public view returns (bool) {
return _getBlocklistableStorage().blocklisted[account];
}

// ------------------ Private functions ----------------------- //

/**
* @dev Returns the contract storage structure.
*/
function _getBlocklistableStorage() private pure returns (BlocklistableStorage storage $) {
assembly {
$.slot := BlocklistableStorageLocation
}
}
}
70 changes: 70 additions & 0 deletions contracts/base/PausableExtUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";

import { AccessControlExtUpgradeable } from "./AccessControlExtUpgradeable.sol";

/**
* @title PausableExtUpgradeable base contract
* @author CloudWalk Inc.
* @dev Extends the OpenZeppelin's {PausableUpgradeable} contract by adding the {PAUSER_ROLE} role.
*
* This contract is used through inheritance. It introduces the {PAUSER_ROLE} role that is allowed to
* trigger the paused or unpaused state of the contract that is inherited from this one.
*/
abstract contract PausableExtUpgradeable is AccessControlExtUpgradeable, PausableUpgradeable {
/// @dev The role of pauser that is allowed to trigger the paused or unpaused state of the contract.
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

// ------------------ Initializers ---------------------------- //

/**
* @dev The internal initializer of the upgradable contract.
*
* See details https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable.
*/
function __PausableExt_init(bytes32 pauserRoleAdmin) internal onlyInitializing {
__Context_init_unchained();
__ERC165_init_unchained();
__AccessControl_init_unchained();
__AccessControlExt_init_unchained();
__Pausable_init_unchained();

__PausableExt_init_unchained(pauserRoleAdmin);
}

/**
* @dev The unchained internal initializer of the upgradable contract.
*
* See {PausableExtUpgradeable-__PausableExt_init}.
*/
function __PausableExt_init_unchained(bytes32 pauserRoleAdmin) internal onlyInitializing {
_setRoleAdmin(PAUSER_ROLE, pauserRoleAdmin);
}

// ------------------ Functions ------------------------------- //

/**
* @dev Triggers the paused state of the contract.
*
* Requirements:
*
* - The caller must have the {PAUSER_ROLE} role.
*/
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}

/**
* @dev Triggers the unpaused state of the contract.
*
* Requirements:
*
* - The caller must have the {PAUSER_ROLE} role.
*/
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
}
Loading

0 comments on commit 79e98ef

Please sign in to comment.