Overview
ETH Balance
0 ETH
Eth Value
$0.00Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0x59f2b254d440e366a694ceaa307e651df79be3d7
Contract Name:
Escrow
Compiler Version
v0.6.6+commit.6c089d02
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2020-05-01
*/
// File: @openzeppelin/contracts/math/SafeMath.sol
pragma solidity ^0.6.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// File: @openzeppelin/contracts/cryptography/ECDSA.sol
pragma solidity ^0.6.0;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Check the signature length
if (signature.length != 65) {
revert("ECDSA: invalid signature length");
}
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solhint-disable-next-line no-inline-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
revert("ECDSA: invalid signature 's' value");
}
if (v != 27 && v != 28) {
revert("ECDSA: invalid signature 'v' value");
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* replicates the behavior of the
* https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
* JSON-RPC method.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
}
// File: contracts/Escrow.sol
pragma solidity ^0.6.0;
/**
* @dev Escrow contract for ETH based escrows
*/
contract Escrow {
using SafeMath for uint256;
using ECDSA for bytes32;
event FundsDeposited(address indexed buyer, uint256 amount);
event FundsRefunded();
event FundsReleased(address indexed seller, uint256 amount);
event DisputeResolved();
event OwnershipTransferred(address indexed oldOwner, address newOwner);
event MediatorChanged(address indexed oldMediator, address newMediator);
enum Status { AWAITING_PAYMENT, PAID, REFUNDED, MEDIATED, COMPLETE }
Status public status;
bytes32 escrowID;
uint256 amount;
uint256 fee;
address payable public owner;
address payable public mediator;
address payable public buyer;
address payable public seller;
bool public initialized = false;
bool public funded = false;
bool public completed = false;
bytes32 public releaseMsgHash;
bytes32 public resolveMsgHash;
modifier onlyExactAmount(uint256 _amount) {
require(_amount == depositAmount(), "Amount needs to be exact.");
_;
}
modifier onlyBuyer() {
require(msg.sender == buyer, "Only the buyer can call this function.");
_;
}
modifier onlyWithBuyerSignature(bytes32 hash, bytes memory signature) {
require(
hash.toEthSignedMessageHash()
.recover(signature) == buyer,
"Must be signed by buyer."
);
_;
}
modifier onlyWithParticipantSignature(bytes32 hash, bytes memory signature) {
address signer = hash.toEthSignedMessageHash()
.recover(signature);
require(
signer == buyer || signer == seller,
"Must be signed by either buyer or seller."
);
_;
}
modifier onlySeller() {
require(msg.sender == seller, "Only the seller can call this function.");
_;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can call this function.");
_;
}
modifier onlyMediator() {
require(msg.sender == mediator, "Only the mediator can call this function.");
_;
}
modifier onlyUninitialized() {
require(initialized == false, "Escrow already initialized.");
initialized = true;
_;
}
modifier onlyUnfunded() {
require(funded == false, "Escrow already funded.");
funded = true;
_;
}
modifier onlyFunded() {
require(funded == true, "Escrow not funded.");
_;
}
modifier onlyIncompleted() {
require(completed == false, "Escrow already completed.");
completed = true;
_;
}
function init(
bytes32 _escrowID,
address payable _owner,
address payable _buyer,
address payable _seller,
address payable _mediator,
uint256 _amount,
uint256 _fee
)
external
onlyUninitialized
{
status = Status.AWAITING_PAYMENT;
escrowID = _escrowID;
owner = _owner;
buyer = _buyer;
seller = _seller;
mediator = _mediator;
amount = _amount;
fee = _fee;
releaseMsgHash = keccak256(
abi.encodePacked("releaseFunds()", escrowID, address(this))
);
resolveMsgHash = keccak256(
abi.encodePacked("resolveDispute()", escrowID, address(this))
);
emit OwnershipTransferred(address(0), _owner);
emit MediatorChanged(address(0), _owner);
}
fallback() external payable {
deposit();
}
function depositAmount() public view returns (uint256) {
return amount.add(fee);
}
function deposit()
public
payable
onlyUnfunded
onlyExactAmount(msg.value)
{
status = Status.PAID;
emit FundsDeposited(msg.sender, msg.value);
}
function refund()
public
onlySeller
onlyFunded
onlyIncompleted
{
buyer.transfer(depositAmount());
status = Status.REFUNDED;
emit FundsRefunded();
}
function _releaseFees() private {
mediator.transfer(fee.mul(2));
}
function releaseFunds(
bytes calldata _signature
)
external
onlyFunded
onlyIncompleted
onlyWithBuyerSignature(releaseMsgHash, _signature)
{
uint256 releaseAmount = depositAmount().sub(fee.mul(2));
status = Status.COMPLETE;
emit FundsReleased(seller, releaseAmount);
seller.transfer(releaseAmount);
_releaseFees();
}
function resolveDispute(
bytes calldata _signature,
uint8 _buyerPercent
)
external
onlyFunded
onlyMediator
onlyIncompleted
onlyWithParticipantSignature(resolveMsgHash, _signature)
{
require(_buyerPercent <= 100, "_buyerPercent must be 100 or lower");
uint256 releaseAmount = depositAmount().sub(fee.mul(2));
status = Status.MEDIATED;
emit DisputeResolved();
if (_buyerPercent > 0)
buyer.transfer(releaseAmount.mul(uint256(_buyerPercent)).div(100));
if (_buyerPercent < 100)
seller.transfer(releaseAmount.mul(uint256(100).sub(_buyerPercent)).div(100));
_releaseFees();
}
function setOwner(address payable _newOwner) external onlyOwner {
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
function setMediator(address payable _newMediator) external onlyOwner {
emit MediatorChanged(mediator, _newMediator);
mediator = _newMediator;
}
}Contract ABI
API[{"anonymous":false,"inputs":[],"name":"DisputeResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsDeposited","type":"event"},{"anonymous":false,"inputs":[],"name":"FundsRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMediator","type":"address"},{"indexed":false,"internalType":"address","name":"newMediator","type":"address"}],"name":"MediatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"buyer","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"completed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"funded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_escrowID","type":"bytes32"},{"internalType":"address payable","name":"_owner","type":"address"},{"internalType":"address payable","name":"_buyer","type":"address"},{"internalType":"address payable","name":"_seller","type":"address"},{"internalType":"address payable","name":"_mediator","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mediator","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"releaseFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"releaseMsgHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"uint8","name":"_buyerPercent","type":"uint8"}],"name":"resolveDispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resolveMsgHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seller","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newMediator","type":"address"}],"name":"setMediator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum Escrow.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.