// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)pragmasolidity ^0.8.20;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/errorAddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/errorAddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/errorFailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
if (address(this).balance< amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value) internalreturns (bytesmemory) {
if (address(this).balance< value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/functionverifyCallResultFromTarget(address target,
bool success,
bytesmemory returndata
) internalviewreturns (bytesmemory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty// otherwise we already know that it was a contractif (returndata.length==0&& target.code.length==0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/functionverifyCallResult(bool success, bytesmemory returndata) internalpurereturns (bytesmemory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/function_revert(bytesmemory returndata) privatepure{
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
Contract Source Code
File 2 of 8: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)pragmasolidity ^0.8.20;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
function_contextSuffixLength() internalviewvirtualreturns (uint256) {
return0;
}
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)pragmasolidity ^0.8.20;import {Context} from"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/errorOwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/errorOwnableInvalidOwner(address owner);
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/constructor(address initialOwner) {
if (initialOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
if (newOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 6 of 8: P2POrderManager.sol
// SPDX-License-Identifier: MIT// ENVELOP(NIFTSY) protocol for NFT. pragmasolidity 0.8.26;import"@envelop-protocol-v2/src/utils/TokenService.sol";
import {ReentrancyGuard} from"@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import"@openzeppelin/contracts/access/Ownable.sol";
import"./interface/IOrderStorage.sol";
contractP2POrderManagerisTokenService, ReentrancyGuard, Ownable{
// struct OBRegistryItem {// address orderBookAddress;// bool isEnabled;// }uint256public FEE_PERCENT_DENOMINATOR =10000;
addresspublicimmutable FEE_BENEFICIARY;
uint256publicimmutable FEE_PERCENT;
// map asset type and orderbook addressmapping(ET.AssetType =>address) public orderBooks;
// map orderbook address and status for support old orderbooksmapping(address=>bool) public orderBooksStatus;
eventEnvelopP2POrderTaked(addressindexed AssetAddress,
uint256indexed TokenId,
bytes32indexed OrderId,
address OrderMaker,
address OrderTaker,
address PayToken,
uint256 PayAmount,
uint8 OrderType
);
errorErrorDeleteOrder(bytes32 OrderId);
constructor (uint256 _feePercent, address _feeBeneficiary)
Ownable(msg.sender)
{
FEE_BENEFICIARY = _feeBeneficiary;
FEE_PERCENT = _feePercent;
}
functionmakeOrder(
ET.AssetItem memory _assetItem,
ET.Price calldata _price,
ET.OrderType _ordeType
) externalreturns (bytes32 orderId) {
orderId = IOrderStorage(
orderBooks[_assetItem.asset.assetType]
).makeOrder(_assetItem, _price, _ordeType, msg.sender);
}
functionremoveOrder(bytes32 _orderId,
ET.AssetItem memory _assetItem
) externalreturns(bool deleted){
deleted = IOrderStorage(
orderBooks[_assetItem.asset.assetType]
).removeOrder(_orderId, _assetItem, msg.sender);
}
functiontakeOrder(bytes32 _orderId,
address _orderBook,
ET.OrderType _orderType,
ET.AssetItem memory _assetItem
)
externalpayablenonReentrant{
address _currentAssetOwner = _ownerOf(_assetItem);
// Check that _orderBook addres is validrequire(orderBooksStatus[_orderBook], "OrderBook is not enabled");
(ET.Price memory p, address payer, address maker) = IOrderStorage(
orderBooks[_assetItem.asset.assetType]
).getPriceForOrder(_orderId, _orderType, _assetItem);
if (payer ==address(0)) {
payer =msg.sender;
}
// TODO Check that orderMaker cant take orderif (_orderType == ET.OrderType.BUY) {
require(msg.sender== _currentAssetOwner, "Only asset owner can take BUY order");
}
// Remove order from orderbookif (!
IOrderStorage(_orderBook).removeOrder(
_orderId,
_assetItem,
maker
)
) {
revert ErrorDeleteOrder(_orderId);
}
// Check change in case NATIVE paymentuint256 change;
if (p.payToken ==address(0)) {
change =msg.value- p.payAmount;
}
// Process payment: charge FEEuint256 feeAmount = p.payAmount * FEE_PERCENT/ (100* FEE_PERCENT_DENOMINATOR);
if (FEE_BENEFICIARY !=address(0)){
p.payAmount -= _transferSafe(
ET.AssetItem(
ET.Asset(
p.payToken ==address(0) ? ET.AssetType.NATIVE : ET.AssetType.ERC20,
p.payToken
), 0, feeAmount
),
payer,
FEE_BENEFICIARY
);
}
// Process payment: body
_transfer(
ET.AssetItem(
ET.Asset(
p.payToken ==address(0) ? ET.AssetType.NATIVE : ET.AssetType.ERC20,
p.payToken
), 0, p.payAmount
), payer, _currentAssetOwner
);
// Delivery asset from Order
_transfer(_assetItem, _currentAssetOwner, payer);
if (change >0) {
addresspayable s =payable(payer);
s.transfer(change);
}
emit EnvelopP2POrderTaked(
_assetItem.asset.contractAddress, //AssetAddress,
_assetItem.tokenId, //TokenId,
_orderId, // OrderId,
maker, // OrderMaker,msg.sender, //OrderTaker,
p.payToken, //PayToken,
p.payAmount, //PayAmount,uint8(_orderType) // OrderType
);
}
/////////////////////////////////////////////////////////////// Admin functions ///////////////////////////////////////////////////////////////////////////////////////functionsetOrderBookAddressForAssetType(
ET.AssetType _contractType,
address _orderBookAddress
)
externalonlyOwner{
require(_orderBookAddress !=address(0), "No Zero address");
orderBooks[_contractType] = _orderBookAddress;
orderBooksStatus[_orderBookAddress] =true;
}
functionsetOrderBookStatus(address _orderBookAddress,
bool _status
)
externalonlyOwner{
require(_orderBookAddress !=address(0), "No Zero address");
orderBooksStatus[_orderBookAddress] = _status;
}
////////////////////////////////////////////////////////////functiongetOrdersForItem(ET.AssetItem memory _assetItem)
externalviewreturns(ET.Order[] memory orderList)
{
return IOrderStorage(
orderBooks[_assetItem.asset.assetType]
).getOrdersForItem(_assetItem);
}
}
Contract Source Code
File 7 of 8: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)pragmasolidity ^0.8.20;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant NOT_ENTERED =1;
uint256privateconstant ENTERED =2;
uint256private _status;
/**
* @dev Unauthorized reentrant call.
*/errorReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be NOT_ENTEREDif (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/function_reentrancyGuardEntered() internalviewreturns (bool) {
return _status == ENTERED;
}
}