Skip to content

Instantly share code, notes, and snippets.

@z0r0z
Created December 13, 2021 22:04
Show Gist options
  • Select an option

  • Save z0r0z/82f0c075d368bcc0962b3abc7f476cd3 to your computer and use it in GitHub Desktop.

Select an option

Save z0r0z/82f0c075d368bcc0962b3abc7f476cd3 to your computer and use it in GitHub Desktop.
Escrow for NFT and ERC20 using IERC20
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.0;
/// @notice Standard ERC-20 token interface with EIP-2612 {permit} extension.
interface IERC20 {
/// @dev ERC-20:
function allowance(address owner, address spender) external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function totalSupply() external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 amount);
event Transfer(address indexed from, address indexed to, uint256 amount);
/// @dev EIP-2612:
function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
}
/// @notice Simple bilateral escrow for ETH and ERC-20/721 tokens.
contract Escrow {
uint256 public escrowCount;
mapping(uint256 => Escrow) public escrows;
event Deposit(
bool nft,
address indexed depositor,
address indexed receiver,
IERC20 token,
uint256 amount,
uint256 indexed registration,
string details);
event Release(uint256 indexed registration);
struct Escrow {
bool nft;
address depositor;
address receiver;
IERC20 token;
uint256 value;
}
/// @notice Deposits ETH/ERC-20 into escrow.
/// @param receiver The account that receives funds.
/// @param token The asset used for funds.
/// @param value The amount of funds.
/// @param details Describes context of escrow - stamped into event.
function deposit(address receiver, IERC20 token, uint256 value, string memory details) payable public virtual {
if (address(token) == address(0)) {
require(msg.value == value, "WRONG_MSG_VALUE");
} else {
token.transferFrom(msg.sender, address(this), value);
}
/// @dev Increment registered escrows and assign # to escrow deposit.
unchecked {
escrowCount++;
}
uint256 registration = escrowCount;
escrows[registration] = Escrow(false, msg.sender, receiver, token, value);
emit Deposit(false, msg.sender, receiver, token, value, registration, details);
}
/// @notice Deposits ERC-721 into escrow.
/// @param receiver The account that receives `tokenId`.
/// @param token The NFT asset.
/// @param tokenId The NFT `tokenId`.
/// @param details Describes context of escrow - stamped into event.
function depositNFT(address receiver, IERC20 token, uint256 tokenId, string memory details) public virtual {
token.transferFrom(msg.sender, address(this), tokenId);
/// @dev Increment registered escrows and assign # to escrow deposit.
unchecked {
escrowCount++;
}
uint256 registration = escrowCount;
escrows[registration] = Escrow(true, msg.sender, receiver, token, tokenId);
emit Deposit(true, msg.sender, receiver, token, tokenId, registration, details);
}
/// @notice Releases escrowed assets to designated `receiver`.
/// @param registration The index of escrow deposit.
function release(uint256 registration) public virtual {
Escrow storage escrow = escrows[registration];
require(msg.sender == escrow.depositor, "NOT_DEPOSITOR");
require(!escrow.nft, "NFT");
if (address(escrow.token) == address(0)) {
(bool success, ) = escrow.receiver.call{value: escrow.value}("");
require(success, "ETH_TRANSFER_FAILED");
} else {
escrow.token.transfer(escrow.receiver, escrow.value);
}
emit Release(registration);
}
/// @notice Releases escrowed NFT `tokenId` to designated `receiver`.
/// @param registration The index of escrow deposit.
function releaseNFT(uint256 registration) public virtual {
Escrow storage escrow = escrows[registration];
require(msg.sender == escrow.depositor, "NOT_DEPOSITOR");
require(escrow.nft, "NOT_NFT");
escrow.token.transferFrom(address(this), escrow.receiver, escrow.value);
emit Release(registration);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment