ForwardContract.sol is a decentralized forward trading contract written in Solidity. It enables a buyer and seller to enter a forward agreement to exchange ETH for USDC at a future date for a fixed price.
This smart contract ensures:
- Secure escrow of ETH and USDC between both parties
- Mutual rejection before settlement date
- Automatic settlement after expiry
- Strict access control for buyer and seller actions
MasterPrem
📜 SPDX-License-Identifier: MIT
💡 Solidity Version: ^0.8.18
- 🧱 Forward Contract Setup: Define buyer, seller, strike price, ETH amount, and settlement date
- 💰 Deposit System: Seller deposits ETH, Buyer deposits USDC (ERC20 token)
- ⏳ Timed Settlement: Automatically settles after the specified settlement date
- ❌ Mutual Rejection: Both parties can cancel before settlement date
- 🔒 Access Control: Only involved parties can interact with trade functions
- 🧮 Detailed Getters: View contract details, balances, and contract state
| Function | Description |
|---|---|
setUp() |
Initializes the forward contract between buyer and seller |
depositEther() |
Allows seller to deposit ETH |
depositUSDC() |
Allows buyer to deposit USDC tokens |
executeForward() |
Executes trade once settlement date is reached |
rejectContract() |
Allows mutual rejection before settlement date |
getContractDetails() |
Returns buyer, seller, strike price, and ETH amount |
getUSDCBalance() |
Returns contract’s current USDC balance |
getForwardContractState() |
Returns the contract status (Ongoing / Closed) |
flowchart TD
A[Set Up Contract] --> B[Seller Deposits ETH]
B --> C[Buyer Deposits USDC]
C --> H[Before Settlement Date]
C --> D[Wait Until Settlement Date]
D -->|If Both Agree| E[Execute Forward - Trade Happens]
H -->|If both Rejects| F[Reject Contract - Funds Returned]
E --> G[Contract Closed]
F --> G
- Solidity: Smart Contract Language
- Hardhat / Foundry: For testing and deployment
- OpenZeppelin (optional): For ERC20 token interface
- FakeUSDC Token (Test ERC20): Simulated USDC token
Ensure you have the following installed:
- Node.js (>= 16.x)
- npm or yarn
- Hardhat or Foundry
- MetaMask (for interacting on testnet)
- FakeUSDC token contract deployed for testing
git clone https://github.com/<your-username>/ForwardSmartContract.git
cd ForwardSmartContractIf using Hardhat:
npm install --save-dev hardhat @nomicfoundation/hardhat-toolboxIf using Foundry:
forge initFor Hardhat:
npx hardhat compileFor Foundry:
forge buildEdit the deployment script (deploy.js or DeployForward.s.sol) with your constructor parameters, then run:
For Hardhat (using Sepolia):
npx hardhat run scripts/deploy.js --network sepoliaFor Foundry:
forge script script/DeployForward.s.sol --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY --broadcastIf you have test cases (e.g., ForwardContractTest.t.sol), run:
forge testor with Hardhat:
npx hardhat testPerfect 👍 — here’s your Remix-friendly version of the Forward Contract setup and execution steps — rewritten clearly so you can copy and follow them directly in Remix IDE without confusion. Each step includes exact actions, function calls, and example input values for a smooth walkthrough.
After deploying both contracts:
-
Copy the address of:
- The deployed FakeUSDC token (e.g.,
0x...FakeUSDC) - The buyer (use another Remix account)
- The seller (use your first Remix account)
- The deployed FakeUSDC token (e.g.,
-
Select the deployed ForwardContract in Remix.
-
In the setUp function, enter the parameters:
_buyer: 0xBuyerAddress
_seller: 0xSellerAddress
_usdcToken: 0xFakeUSDCAddress
_strikePrice: 200000000 // 200 * 1e6 (for USDC with 6 decimals)
_ethAmount_in_wei: 10000000000000000000 // 1 ETH = 1e18 wei
_settlementDate: <current timestamp + 600> // e.g., 10 mins later for testing
this is [UNIX Timestamp](https://www.unixtimestamp.com/)
📘 Example:
setUp(
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4,
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2,
0x8A791620dd6260079BF849Dc5567aDC3F2FdC318,
2000000000,
1000000000000000000,
1728660000
)
✅ This sets up the forward agreement between buyer and seller.
Now, from the seller’s account (the one you used in setUp):
- Switch Remix account to the seller.
- Select the
depositEtherfunction. - In the Value (ETH) field (top of Remix panel), enter
10(to send 10 ETH). - Click transact.
✅ Expected result:
- Contract now holds
10 ETH. - Seller’s deposit recorded successfully.
ForwardContract_IncorrectEthAmount().
Now, switch to the buyer’s account in Remix.
- Open the deployed FakeUSDC contract.
- Call the
approve()function:
spender: <ForwardContract address>
amount: 200000000 // 200 * 1e6 (for 6-decimal USDC)
- Click transact to allow the ForwardContract to spend the buyer’s USDC.
✅ Once approval succeeds, open the ForwardContract again and call:
depositUSDC()
✅ Expected result:
- Contract now holds 200 USDC.
- Buyer’s payment is locked in escrow.
ForwardContract_TransferFailed() error.
Both ETH and USDC are now locked inside the contract.
You can check:
getUSDCBalance()→ should show200000000getContractDetails()→ confirm buyer/seller/amounts
⏱ Wait until the settlement date (timestamp) is reached. In Remix VM, you can simulate this by:
- Clicking the "Increase Time" button under Remix Debugger > Time Travel plugin (optional), or
- Simply redeploy with a small wait time (e.g., +2 minutes).
executeForward() before the time →
ForwardContract_SettlementDateHasYetToArrive() error.
Once the settlement date is reached:
-
Either buyer or seller can call:
executeForward() -
Click transact.
✅ Expected result:
200 USDCsent → Seller10 ETHsent → Buyer- Contract marked as Closed
ForwardContract_ContractIsSettled() error.
If both parties want to cancel the trade before settlement date:
-
Buyer calls:
rejectContract() -
Then Seller calls:
rejectContract()
✅ Once both have called:
- ETH returned to Seller
- USDC returned to Buyer
- Contract marked as Closed
ForwardContract_CannotRejectAfterSettlementDate() error.
| Step | Role | Function | Remix Action |
|---|---|---|---|
| 1 | Deployer | setUp() |
Enter all parameters |
| 2 | Seller | depositEther() |
Send 10 ETH as value |
| 3 | Buyer | approve() in FakeUSDC |
Allow spending by contract |
| 4 | Buyer | depositUSDC() |
Deposit 200 USDC |
| 5 | Either | executeForward() |
After settlement date |
| 6 | Buyer + Seller | rejectContract() |
Both reject before expiry |
setUp(
0xBuyerAddress,
0xSellerAddress,
0xFakeUSDCAddress,
200 * 1e6, // Strike price in USDC (2,000 USDC)
10 ether, // ETH Amount
block.timestamp + 7 days // Settlement date
);- Contract supports mutual rejection only before settlement date.
- Only buyer and seller can interact with deposit and settlement functions.
- Funds are held securely in escrow until settlement or rejection.
- ⛓️ Chainlink Oracle integration for real ETH/USD prices
- 🧠 Automated settlement via off-chain bot
- 🪙 Support for multiple ERC20 stablecoins
- 📅 Partial settlements or rolling forward contracts
This project is licensed under the MIT License. See the LICENSE file for details.
💼 Author: @MasterPrem 📧 Email: masterprem001@egmail.com 🔗 GitHub Repo: Forward Smart Contract
Would you like me to:
- Add a
FakeUSDC.solmock token section in the README (for testing)? - Or make this README GitHub-styled with emojis, code formatting, and a deployment guide using Hardhat commands and example scripts?