Architecture
The contract is intentionally compact. That simplicity is useful, but it makes understanding the state machine of utmost importance.
Components
IERC20
A minimal ERC-20 interface. The escrow contract relies on transferFrom while funding and transfer while refunding or withdrawing.
FeeLibrary
The library performs basis-point calculations using 10,000 as the denominator.
100 bps = 1%
500 bps = 5%
1000 bps = 10%The constructor rejects fees above 1000 basis points.
EscrowContract
The principal state is:
uint256 public nextEscrowId = 1;
mapping(uint256 => Escrow) public escrows;
mapping(address => mapping(address => uint256)) public userBalances;
uint256 public platformFeeBps;
address public platformWallet;The nested balance mapping is germane because balances are tracked per user and per token.
MockToken
A small mock ERC-20-style token is included in the same file for demonstration. It is not an OpenZeppelin ERC-20 implementation.
Escrow data model
struct Escrow {
address client;
address freelancer;
uint256 amount;
address token;
uint256 deadline;
Status status;
}State model
Created
│
│ fundEscrow()
▼
Funded
├──────── requestRefund() after deadline ────────► Refunded
│
│ deliverWork()
▼
Delivered
│
│ approveWork()
▼
ApprovedThere is no implemented transition out of Approved or Refunded, and there is no refund path once the freelancer moves an escrow to Delivered.
Payment accounting
Approval credits internal balances first. The freelancer and platform later call withdraw() to move ERC-20 tokens from the contract to their wallets.