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

pawnshop erc2771 #213

Merged
merged 1 commit into from
Dec 29, 2023
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
51 changes: 51 additions & 0 deletions contracts/loan/ERC2771Context.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.1;

/**
* @dev Context variant with ERC2771 support.
*/
// based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol
abstract contract ERC2771Context {

// for whitelist new relayers need to add new constants and update proxies/redeploy contracts
// address private constant GELATO_RELAY = 0xaBcC9b596420A9E9172FD5938620E265a0f9Df92;
// address private constant GELATO_RELAY_ERC_2771 = 0xb539068872230f20456CF38EC52EF2f91AF4AE49;
// address private constant GELATO_RELAY_CONCURRENT_ERC_2771 = 0x8598806401A63Ddf52473F1B3C55bC9E33e2d73b;
// address private constant GELATO_RELAY_1_BALANCE = 0x75bA5Af8EFFDCFca32E1e288806d54277D1fde99;
address private constant GELATO_RELAY_1_BALANCE_ERC_2771 = 0xd8253782c45a12053594b9deB72d8e8aB2Fca54c;
// address private constant GELATO_RELAY_1_BALANCE_CONCURRENT_ERC_2771 = 0xc65d82ECE367EF06bf2AB791B3f3CF037Dc0e816;

function isTrustedForwarder(address forwarder) public view virtual returns (bool){
return forwarder == GELATO_RELAY_1_BALANCE_ERC_2771;
}

function _msgSender() internal view virtual returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
/// @solidity memory-safe-assembly
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
return sender;
} else {
return msg.sender;
}
}

function _msgData() internal view virtual returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[: msg.data.length - 20];
} else {
return msg.data;
}
}

/// @notice Return true if given address is not a smart contract but a wallet address.
/// @dev It is not 100% guarantee after EIP-3074 implementation, use it as an additional check.
/// @return true if the address is a wallet.
function _isNotSmartContract() internal view returns (bool) {
return isTrustedForwarder(msg.sender) || msg.sender == tx.origin;
}
}
45 changes: 23 additions & 22 deletions contracts/loan/TetuPawnShop.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "../openzeppelin/IERC20.sol";
import "../openzeppelin/ReentrancyGuard.sol";
import "../base/ArrayLib.sol";
import "./ITetuPawnShop.sol";
import "./ERC2771Context.sol";

interface IDelegation {
function clearDelegate(bytes32 _id) external;
Expand All @@ -31,15 +32,15 @@ interface IDelegation {
/// The contract's modular design allows for easy customization of fees, waiting periods,
/// and other parameters, providing a solid foundation for a decentralized borrowing and lending platform.
/// @author belbix
contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop, ERC2771Context {
using SafeERC20 for IERC20;
using ArrayLib for uint[];

// ---- CONSTANTS

/// @notice Version of the contract
/// @dev Should be incremented when contract changed
string public constant VERSION = "1.0.6";
string public constant VERSION = "1.0.7";
/// @dev Time lock for any governance actions
uint constant public TIME_LOCK = 2 days;
/// @dev Denominator for any internal computation with low precision
Expand Down Expand Up @@ -120,7 +121,7 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
}

modifier onlyOwner() {
require(msg.sender == owner, "TPS: Not owner");
require(_msgSender() == owner, "TPS: Not owner");
_;
}

Expand Down Expand Up @@ -191,7 +192,7 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {

pos = Position(
positionCounter, // id
msg.sender, // borrower
_msgSender(), // borrower
positionDepositToken,
positionDepositAmount,
true, // open
Expand All @@ -212,16 +213,16 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
positionsByAcquired[_acquiredToken].push(pos.id);
posIndexes[IndexType.BY_ACQUIRED][pos.id] = positionsByAcquired[_acquiredToken].length - 1;

borrowerPositions[msg.sender].push(pos.id);
posIndexes[IndexType.BORROWER_POSITION][pos.id] = borrowerPositions[msg.sender].length - 1;
borrowerPositions[_msgSender()].push(pos.id);
posIndexes[IndexType.BORROWER_POSITION][pos.id] = borrowerPositions[_msgSender()].length - 1;

positions[pos.id] = pos;
positionCounter++;

_takeDeposit(pos.id);
_transferCollateral(pos.collateral, msg.sender, address(this));
_transferCollateral(pos.collateral, _msgSender(), address(this));
emit PositionOpened(
msg.sender,
_msgSender(),
pos.id,
_collateralToken,
_collateralAmount,
Expand All @@ -238,7 +239,7 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
function closePosition(uint id) external nonReentrant override {
Position storage pos = positions[id];
require(pos.id == id, "TPS: Wrong ID");
require(pos.borrower == msg.sender, "TPS: Only borrower can close a position");
require(pos.borrower == _msgSender(), "TPS: Only borrower can close a position");
require(pos.execution.lender == address(0), "TPS: Can't close executed position");
require(pos.open, "TPS: Position closed");

Expand All @@ -248,7 +249,7 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
_transferCollateral(pos.collateral, address(this), pos.borrower);
_returnDeposit(id);
pos.open = false;
emit PositionClosed(msg.sender, id);
emit PositionClosed(_msgSender(), id);
}

/// @inheritdoc ITetuPawnShop
Expand All @@ -259,41 +260,41 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
require(pos.execution.lender == address(0), "TPS: Can't bid executed position");
if (pos.acquired.acquiredAmount != 0) {
require(amount == pos.acquired.acquiredAmount, "TPS: Wrong bid amount");
_executeBid(pos, 0, amount, msg.sender, msg.sender);
_executeBid(pos, 0, amount, _msgSender(), _msgSender());
} else {
_auctionBid(pos, amount, msg.sender);
_auctionBid(pos, amount, _msgSender());
}
}

/// @inheritdoc ITetuPawnShop
function claim(uint id) external nonReentrant override {
Position storage pos = positions[id];
require(pos.id == id, "TPS: Wrong ID");
require(pos.execution.lender == msg.sender, "TPS: Only lender can claim");
require(pos.execution.lender == _msgSender(), "TPS: Only lender can claim");
uint posEnd = pos.execution.posStartBlock + pos.info.posDurationBlocks;
require(posEnd < block.number, "TPS: Too early to claim");
require(pos.open, "TPS: Position closed");

_endPosition(pos);
_transferCollateral(pos.collateral, address(this), msg.sender);
_transferCollateral(pos.collateral, address(this), _msgSender());
_returnDeposit(id);
emit PositionClaimed(msg.sender, id);
emit PositionClaimed(_msgSender(), id);
}

/// @inheritdoc ITetuPawnShop
function redeem(uint id) external nonReentrant override {
Position storage pos = positions[id];
require(pos.id == id, "TPS: Wrong ID");
require(pos.borrower == msg.sender, "TPS: Only borrower can redeem");
require(pos.borrower == _msgSender(), "TPS: Only borrower can redeem");
require(pos.execution.lender != address(0), "TPS: Not executed position");
require(pos.open, "TPS: Position closed");

_endPosition(pos);
uint toSend = _toRedeem(id);
IERC20(pos.acquired.acquiredToken).safeTransferFrom(msg.sender, pos.execution.lender, toSend);
_transferCollateral(pos.collateral, address(this), msg.sender);
IERC20(pos.acquired.acquiredToken).safeTransferFrom(_msgSender(), pos.execution.lender, toSend);
_transferCollateral(pos.collateral, address(this), _msgSender());
_returnDeposit(id);
emit PositionRedeemed(msg.sender, id);
emit PositionRedeemed(_msgSender(), id);
}

/// @inheritdoc ITetuPawnShop
Expand All @@ -308,14 +309,14 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
require(_bid.posId == posId, "TPS: Wrong bid");

Position storage pos = positions[posId];
require(pos.borrower == msg.sender, "TPS: Not borrower");
require(pos.borrower == _msgSender(), "TPS: Not borrower");
require(pos.open, "TPS: Position closed");

pos.acquired.acquiredAmount = _bid.amount;
_executeBid(pos, bidId, _bid.amount, address(this), _bid.lender);
lenderOpenBids[_bid.lender][pos.id] = 0;
_bid.open = false;
emit AuctionBidAccepted(msg.sender, posId, _bid.id);
emit AuctionBidAccepted(_msgSender(), posId, _bid.id);
}

/// @inheritdoc ITetuPawnShop
Expand Down Expand Up @@ -429,7 +430,7 @@ contract TetuPawnShop is ERC721Holder, ReentrancyGuard, ITetuPawnShop {
// write index + 1 for keep zero as empty value
lenderOpenBids[lender][pos.id] = positionToBidIds[pos.id].length;

IERC20(pos.acquired.acquiredToken).safeTransferFrom(msg.sender, address(this), amount);
IERC20(pos.acquired.acquiredToken).safeTransferFrom(_msgSender(), address(this), amount);

lastAuctionBidTs[pos.id] = block.timestamp;
auctionBids[_bid.id] = _bid;
Expand Down
Loading