Back to Home

EscrowFoundry

utility
0xbe7193779e32...a9efa938f389
HomesteadSource Verified
Deployed July 6, 2016 (9 years ago)Block 1,837,364

A factory contract for generating custom escrow agreements between buyers, sellers, and arbiters. Compiled with solc v0.3.5, optimizer on.

Key Facts

Deployment Block
1,837,364
Deployment Date
Jul 6, 2016, 09:12 PM
Code Size
3.0 KB

Description

EscrowFoundry is a factory contract that generates custom EscrowContract instances to protect transactions between two parties. Each escrow is configured with a buyer, seller, arbiter, transaction amount, fee structure, and dispute deadline. The generated EscrowContract supports a full lifecycle: funding, seller acceptance, buyer payment release, dispute resolution, and a fifty-fifty fallback if the arbiter misses the deadline. The developer charged a configurable tip on each escrow. Deployed by 0xd9145ecb on July 6, 2016 and announced on Reddit the same day.

Heuristic Analysis

The following characteristics were detected through bytecode analysis and may not be accurate.

Detected Type: utility

Homestead Era

The first planned hard fork. Removed the canary contract, adjusted gas costs.

Block span: 1,150,0001,919,999
March 14, 2016July 20, 2016

Bytecode Overview

Opcodes3,061
Unique Opcodes176
Jump Instructions207
Storage Operations132

Verified Source Available

This contract has verified source code on Etherscan.

Show source code (Solidity)
contract EscrowContract {

    // TYPES
    enum state {Funding, Paid, Accepted, Dispute, Closed}
    
    // PRIVATE VARIABLES
    address private developer;
    bool private mutex;
    uint256 private dispute_limit;
    
    // PUBLIC VARIABLES
    address public buyer;
    address public seller;
    address public escrow;
    uint256 public amount;
    uint256 public fee;
    uint256 public tip;
    uint256 public dispute_end;
    state public status;
    
    // EVENTS
    event CurrentStatus(uint8 s);
    
    // CONSTRUCTOR
    function EscrowContract(address _developer, address _buyer, address _seller, address _escrow, uint256 _amount, uint256 _fee, uint256 _tip ,uint256 _dispute_limit)
        private
    {
        developer = _developer;
        mutex = false;
        dispute_limit = _dispute_limit;     
        buyer = _buyer;
        seller = _seller;
        escrow = _escrow;
        amount = _amount;
        fee = _fee;
        tip = _tip;
        dispute_end = 0;
        status = state.Funding;
        CurrentStatus(uint8(status));
    }

    // MODIFIERS
    modifier only_when(state s) {
        if (status != s)  throw;
        _
    }
    modifier only_before(state s) {
        if (status >= s)  throw;
        _
    }
    modifier only_buyer() {
        if (msg.sender != buyer) throw;
        _
    }
    modifier only_seller() {
        if (msg.sender != seller) throw;
        _
    }
    modifier only_buyer_seller() {
        if (msg.sender != buyer && msg.sender != seller) throw;
        _
    }
    modifier only_escrow() {
        if (msg.sender != escrow) throw;
        _
    }
    modifier only_no_value() {
        if (msg.value != 0)  throw;
        _
    }
    modifier check_mutex() {
        if (mutex) throw;
        mutex = true;
        _
        mutex = false;
    }
    
    // VALIDATE PERCENT
    function validate_percent(uint8 val)
        private
        constant
    {
        if (val > 100) throw;
    }   

    // BUYER CANCEL
    function buyer_cancel()
        public
        only_before(state.Accepted)
        only_buyer()
        only_no_value()
        check_mutex()
    {
        if (this.balance > 0)
            if (!buyer.send(this.balance)) throw;
        status = state.Closed;
        CurrentStatus(uint8(status));
    }
    
    // SELLER ACCEPT
    function seller_accept()
        public
        only_when(state.Paid)
        only_seller()
        only_no_value()
        check_mutex()
    {
        status = state.Accepted;
        CurrentStatus(uint8(status));
    }

    // BUYER PAY
    function buyer_pay()
        public
        only_when(state.Accepted)
        only_buyer()
        only_no_value()
        check_mutex()
    {
        if (amount > 0)
            if (!seller.send(amount)) throw;
        if (fee > 0)
            if (!buyer.send(fee)) throw;
        if (tip > 0)
            if (!developer.send(tip)) throw;
        status = state.Closed;
        CurrentStatus(uint8(status));
    }

    // DISPUTE
    function dispute()
        public
        only_when(state.Accepted)
        only_buyer_seller()
        only_no_value()
        check_mutex()
    {
        status = state.Dispute;
        dispute_end = block.timestamp + dispute_limit;
        CurrentStatus(uint8(status));
    }

    // RESOLVE
    function resolve(uint8 percent_buyer, uint8 percent_tip)
        public
        only_when(state.Dispute)
        only_escrow()
        only_no_value()
        check_mutex()
    {
        validate_percent(percent_buyer);
        validate_percent(percent_tip);
        uint256 buyer_amount = uint256(amount * percent_buyer)/100;
        uint256 seller_amount = amount - buyer_amount;
        uint256 tip_amount = uint256(fee * percent_tip)/100;
        uint256 escrow_amount = fee - tip_amount;
        tip_amount = tip_amount + tip;
        if (buyer_amount > 0)
            if (!buyer.send(buyer_amount)) throw;
        if (seller_amount > 0)
            if (!seller.send(seller_amount)) throw;
        if (escrow_amount > 0)
            if (!escrow.send(escrow_amount)) throw;
        if (tip_amount > 0)
            if (!developer.send(tip_amount)) throw;
        status = state.Closed;
        CurrentStatus(uint8(status));
    }

    // FIFTY FIFTY
    function fifty_fifty()
        public
        only_when(state.Dispute)
        only_buyer_seller()
        only_no_value()
        check_mutex()
    {
        if (block.timestamp < dispute_end) throw;
        uint256 buyer_amount = uint256(amount * 50)/100;
        uint256 seller_amount = amount - buyer_amount;
        buyer_amount = buyer_amount + fee;
        if (buyer_amount > 0)
            if (!buyer.send(buyer_amount)) throw;
        if (seller_amount > 0)
            if (!seller.send(seller_amount)) throw;
        if (tip > 0)
            if (!developer.send(tip)) throw;
        status = state.Closed;
        CurrentStatus(uint8(status));
    }
    
    // DEFAULT FUNCTION
    function()
        public
        only_before(state.Closed)
        check_mutex()
    {
        if (status == state.Funding) {
            if (this.balance >= (amount + fee + tip)) {
                status = state.Paid;
                CurrentStatus(uint8(status));
            }
        }
        if (status >= state.Paid) tip = this.balance - (amount + fee);
    }
    
}


contract EscrowFoundry {
    
    // PRIVATE VARIABLES
    address private developer;
    
    // EVENTS
    event NewContract(address a);
    
    // CONSTRUCTOR
    function EscrowFoundry() 
        private
    {
        developer = msg.sender;
    }
    
    // MODIFIERS
    modifier only_no_value() {
        if (msg.value != 0)  throw;
        _
    }

    // VALIDATE PERCENT
    function validate_percent(uint8 val)
        private
        constant
    {
        if (val > 100) throw;
    }
    
    // CREATE
    function create(address _buyer, address _seller, address _escrow, uint256 _amount, uint8 _percent_fee, uint8 _percent_tip, uint256 _dispute_limit)
        public
        constant
        only_no_value()
        returns (address)
    {
        validate_percent(_percent_fee);
        validate_percent(_percent_tip);
        uint256 fee = uint256(_amount * _percent_fee)/100;
        uint256 tip = uint256(_amount * _percent_tip)/100;
        EscrowContract c = new EscrowContract(developer, _buyer, _seller, _escrow, _amount, fee, tip, _dispute_limit);
        NewContract(c);
        return c;
    }
    
    // DEFAULT FUNCTION
    function()
        public
    {
        throw;
    }

}

External Links