Skip to content

Commit

Permalink
Merge pull request #213 from tetu-io/dev
Browse files Browse the repository at this point in the history
pawnshop erc2771
  • Loading branch information
belbix authored Dec 29, 2023
2 parents 440db54 + aa7823b commit 6db29b5
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 22 deletions.
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

0 comments on commit 6db29b5

Please sign in to comment.