An Escrow Smart Contract
Follow these steps to set up your environment, deploy an Escrow contract, and interact with it from the Truffle console.
Reference material
GitHub: Chapter 1 (Escrow)
Part 1: Setting Up the Development Environment
Step 1: Install Node.js
- Download and Install Node.js
- Go to the Node.js website.
- Download the LTS version for your OS (Windows, macOS, Linux).
- Follow the installer instructions.
- Verify the Installation
node -v npm -v
You should see version numbers for both.
Step 2: Install Truffle
- Install globally:
npm install -g truffle
- Verify:
truffle version
Step 3: Install Ganache
- Download and install from the Ganache website.
- Start Ganache → Quickstart Ethereum to launch a local blockchain.
Step 4: Set Up a New Truffle Project
- Create the project directory:
mkdir Escrow cd Escrow
- Initialize Truffle:
truffle init
- Configure
truffle-config.js
to connect to Ganache:module.exports = { networks: { development: { host: "127.0.0.1", // Localhost port: 7545, // Ganache port network_id: "*", // Match any network id }, }, compilers: { solc: { version: "0.8.0", // Compiler version }, }, };
Part 2: Creating the Escrow Smart Contract
Step 1: Create the Smart Contract
- In
contracts
, createEscrow.sol
. - Paste the following code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Escrow {
address public buyer;
address public seller;
uint public deposit;
uint public timeToExpiry;
uint public startTime;
// Buyer sets up the escrow contract and pays the deposit
constructor(address _seller, uint _timeToExpiry) payable {
require(msg.value > 0, "Deposit must be greater than zero");
buyer = msg.sender;
seller = _seller;
deposit = msg.value;
timeToExpiry = _timeToExpiry;
startTime = block.timestamp;
}
// Buyer releases deposit to seller
function releaseToSeller() public {
require(msg.sender == buyer, "Only buyer can release funds");
require(!isExpired(), "Escrow is expired");
payable(seller).transfer(deposit);
deposit = 0; // Set deposit to zero to prevent re-entry
}
// Buyer can withdraw deposit if escrow is expired
function withdraw() public {
require(isExpired(), "Escrow is not expired yet");
require(msg.sender == buyer, "Only buyer can withdraw funds");
uint amount = deposit;
deposit = 0; // Set deposit to zero to prevent re-entry
payable(buyer).transfer(amount);
}
// Seller can cancel escrow and return all funds to buyer
function cancel() public {
require(msg.sender == seller, "Only seller can cancel the escrow");
uint amount = deposit;
deposit = 0; // Set deposit to zero to prevent re-entry
payable(buyer).transfer(amount);
}
// Check if the escrow is expired
function isExpired() public view returns (bool) {
return block.timestamp > startTime + timeToExpiry;
}
}
Step 2: Compile
truffle compile
Step 2: Write a Migration Script
Create migrations/2_deploy_contracts.js
const Escrow = artifacts.require("Escrow");
module.exports = function (deployer, network, accounts) {
const sellerAddress = accounts[1]; // Example seller address
const timeToExpiry = 3600; // 1 hour in seconds
deployer.deploy(Escrow, sellerAddress, timeToExpiry, {
value: web3.utils.toWei("1", "ether"), // 1 ETH deposit
from: accounts[0], // Example buyer address
});
};
Deploy the Contract
truffle migrate --reset
This deploys the Escrow contract to your local Ganache network.
Part 3: Interacting with the Escrow Contract
Step 1: Start the Truffle Console
truffle console
Step 2: Interact with the Contract
- Get the deployed instance:
const escrowInstance = await Escrow.deployed();
- Check initial state:
const buyer = await escrowInstance.buyer();
const seller = await escrowInstance.seller();
const deposit = await escrowInstance.deposit();
const timeToExpiry = await escrowInstance.timeToExpiry();
const startTime = await escrowInstance.startTime();
console.log("Buyer:", buyer);
console.log("Seller:", seller);
console.log("Deposit (in wei):", deposit.toString());
console.log("Time to Expiry (seconds):", timeToExpiry.toString());
console.log("Start Time (timestamp):", startTime.toString());
- Call functions:
// Release Funds to Seller
await escrowInstance.releaseToSeller({ from: buyer });
// Withdraw Funds (if expired)
await escrowInstance.withdraw({ from: buyer });
// Cancel Escrow (seller returns funds)
await escrowInstance.cancel({ from: seller });
// Check expiry
const expired = await escrowInstance.isExpired();
console.log("Is the escrow expired?", expired);
Step 4: Testing with Different Accounts
const accounts = await web3.eth.getAccounts();
// As the buyer (account[0])
await escrowInstance.releaseToSeller({ from: accounts[0] });
// As the seller (account[1])
await escrowInstance.cancel({ from: accounts[1] });
Monitoring Transactions in Ganache
While interacting with the contract, watch the Ganache UI for transaction hashes, gas used, and which accounts were affected.
Summary
- Step 1: Set up Node.js, Truffle, and Ganache.
- Step 2: Create and deploy the Escrow smart contract.
- Step 3: Interact with the contract via the Truffle console and monitor in Ganache.