Release path
After fiat payment is confirmed off-chain, the seller releases escrowed crypto to the buyer. A platform fee can be routed to a fee recipient if configured.
A transparent ERC20 escrow design for locking crypto during P2P trades, with seller release, timeout refund, and arbiter dispute resolution.
CoinRep Standard
Clear rules before action
The contract holds ERC20 tokens for a trade until the seller releases to the buyer, the seller refunds after expiry, or an arbiter resolves a dispute.
A trade records the buyer, seller, token, amount, expiry time, and current state. The seller funds the escrow by transferring the exact token amount into the contract.
After fiat payment is confirmed off-chain, the seller releases escrowed crypto to the buyer. A platform fee can be routed to a fee recipient if configured.
If the trade expires without payment confirmation, the seller can refund the escrowed crypto back to their own wallet.
Either party can mark a funded trade as disputed. The arbiter can then resolve funds to buyer, seller, or split between both parties.
The owner can pause new sensitive actions, update the arbiter, and configure a capped fee recipient for released trades.
The seller funds a created trade by transferring the exact ERC20 amount into the contract. Once funded, the trade can move to release, refund, or dispute resolution. This mirrors the trade-room flow users already see on CoinRep.
Created: trade exists but token is not locked yet.
Funded: token has moved into escrow.
Released: buyer receives crypto after payment confirmation.
Disputed: arbiter can split or resolve funds.
function fundTrade(uint256 tradeId) external nonReentrant whenNotPaused {
Trade storage trade = trades[tradeId];
require(msg.sender == trade.seller, "Only seller funds");
require(trade.status == TradeStatus.Created, "Trade not fundable");
trade.status = TradeStatus.Funded;
trade.fundedAt = block.timestamp;
trade.token.safeTransferFrom(msg.sender, address(this), trade.amount);
}