A decentralized application (dApp) for purchasing, managing, and redeeming Euro-denominated vouchers as NFTs on the Monad blockchain.
- Overview
- Euro Banknote Gallery
- Features
- Live Demo
- Smart Contract
- Architecture
- Installation
- Usage
- Smart Contract Functions
- NFT Metadata
- Tech Stack
- License
The Euro Voucher NFT System allows users to:
- Purchase Euro-denominated vouchers (5€, 10€, 20€, 50€, 100€, 500€) using MON tokens
- Receive ERC-721 NFTs representing their vouchers
- Transfer vouchers between wallets
- Redeem vouchers when needed
- Track purchase history and timestamps
Each NFT voucher contains:
- Euro value
- Purchase price in MON
- Unique voucher ID
- Purchase timestamp
- Redemption status
- Beautiful euro banknote imagery
| Denomination | Image | Price (MON) |
|---|---|---|
| 5€ | ![]() |
100 MON |
| 10€ | ![]() |
200 MON |
| 20€ | ![]() |
300 MON |
| 50€ | ![]() |
500 MON |
| 100€ | ![]() |
1,000 MON |
| 500€ | ![]() |
5,000 MON |
- ✅ MetaMask wallet connection
- ✅ Automatic Monad network detection/switching
- ✅ Visual voucher selection (6 denominations)
- ✅ Real-time transaction status
- ✅ Voucher details reader
- ✅ Responsive neon-themed UI
- ✅ Euro banknote images on each voucher
- ✅ ERC-721 compliant NFTs
- ✅ Dynamic pricing system
- ✅ Ownership tracking
- ✅ Redemption mechanism
- ✅ Transfer functionality
- ✅ Owner-only admin functions
- ✅ Event emission for tracking
- ✅ On-chain metadata
- ✅ Unique voucher IDs
- ✅ Purchase timestamps
- ✅ Euro banknote images
- ✅ QR code data support
Frontend: https://euro-voucher-frontend.vercel.app
Metadata API: https://euro-voucher-metadata.vercel.app
Explorer: View Contract on Monad Explorer
const VAULT_ADDRESS = 0xE00454506f50ac31A0b87324513e28f77Db2a8F9
const SWAP_ROUTER_ADDRESS = 0x334cf8898EecCC0B98420E6910A3ae83A00b32e0
Contract Address: 0xa4d064E4ac881234961C076d314Abf9ac8d4E4BB
Network: Monad Mainnet (Chain ID: 143)
Token Standard: ERC-721
Name: Euro Voucher NFT
Symbol: EVNFT
┌─────────────────┐
│ User Wallet │
│ (MetaMask) │
└────────┬────────┘
│
↓
┌─────────────────┐ ┌──────────────────┐
│ Frontend │─────→│ Smart Contract │
│ (Vercel) │ │ (Monad Chain) │
└─────────────────┘ └────────┬─────────┘
│
↓
┌──────────────────┐
│ Metadata API │
│ (Vercel) │
└──────────────────┘
-
Frontend (HTML/JS/Tailwind)
- User interface for buying/reading vouchers
- Web3.js integration for blockchain interaction
- Deployed on Vercel
-
Smart Contract (Solidity)
- ERC-721 NFT implementation
- Voucher logic and state management
- Deployed on Monad blockchain
-
Metadata API (Node.js/Express)
- Serves NFT metadata (JSON)
- Returns euro banknote images
- OpenSea-compatible format
- Node.js v16+
- MetaMask browser extension
- Git
git clone https://github.com/yourusername/euro-voucher-nft.git
cd euro-voucher-nftcd frontend
# No build required - it's a static HTML file
# Just open index.html in browser or deploy to Vercel
vercel --prodcd metadata-api
npm install
npm start
# Or deploy to Vercel
vercel --prod- Click "CONNECT TO MONAD"
- Approve MetaMask connection
- Switch to Monad network if needed
- Select denomination (5€ - 500€)
- Click "BUY" button
- Confirm transaction in MetaMask
- Receive NFT in your wallet
- Enter Token ID
- Click "Read Voucher"
- View all voucher details
- Use MetaMask to send NFT
- Or call
transferFrom()function
- Call
redeemVoucher(tokenId)when ready to use
Get complete voucher information.
Returns:
euroValue- Denomination (5, 10, 20, 50, 100, 500)pricePaidMON- Price paid in MON (wei)buyer- Wallet address of purchaserpurchaseTimestamp- Unix timestampredeemed- Redemption status (bool)voucherId- Unique voucher ID string
Example:
const voucher = await contract.methods.getVoucher(1).call();
console.log(voucher);
// Output: [50, "500000000000000000000", "0xABC...", 1737380000, false, "VOC-123"]Get current price for a denomination.
Parameters:
euroValue- Euro denomination (5, 10, 20, 50, 100, 500)
Returns:
price- Price in MON (wei)
Example:
const price = await contract.methods.getPrice(50).call();
console.log(web3.utils.fromWei(price, 'ether')); // "500"Get all token IDs owned by an address.
Parameters:
owner- Wallet address
Returns:
uint256[]- Array of token IDs
Example:
const tokens = await contract.methods.getVouchersByOwner("0xYourAddress").call();
console.log(tokens); // [1, 5, 12, 25]Get number of vouchers owned by address.
Example:
const balance = await contract.methods.balanceOf("0xYourAddress").call();
console.log(balance); // 4Get owner of a specific token.
Example:
const owner = await contract.methods.ownerOf(1).call();
console.log(owner); // "0xABC..."Check if voucher exists and is not redeemed.
Returns:
bool- True if valid and unredeemed
Example:
const valid = await contract.methods.isVoucherValid(1).call();
console.log(valid); // trueGet QR code data string for voucher.
Returns:
string- QR code data
Example:
const qr = await contract.methods.getQRCodeData(1).call();
console.log(qr); // "EURO_VOUCHER:1:50:VOC-123..."Get statistics for a denomination.
Returns:
totalMinted- Total vouchers of this valuecurrentPrice- Current price in MON
Example:
const stats = await contract.methods.getVoucherStats(50).call();
console.log(stats); // [15, "500000000000000000000"]Get metadata URI for NFT (OpenSea compatible).
Returns:
string- Metadata URL
Example:
const uri = await contract.methods.tokenURI(1).call();
console.log(uri);
// "https://euro-voucher-metadata.vercel.app/metadata/1"Get total number of vouchers minted.
Example:
const supply = await contract.methods.totalSupply().call();
console.log(supply); // 42Get contract's MON balance.
Example:
const balance = await contract.methods.getContractBalance().call();
console.log(web3.utils.fromWei(balance, 'ether')); // "5000"Purchase a new voucher NFT.
Parameters:
euroValue- Denomination (5, 10, 20, 50, 100, 500)voucherId- Unique voucher ID string
Payable: Must send exact MON amount
Example:
const price = await contract.methods.getPrice(50).call();
await contract.methods.purchaseVoucher(50, "VOC-123").send({
from: userAddress,
value: price
});Mark voucher as redeemed (only owner can redeem).
Example:
await contract.methods.redeemVoucher(1).send({ from: userAddress });Transfer voucher to another wallet.
Example:
await contract.methods.transferFrom(
userAddress,
"0xRecipient...",
1
).send({ from: userAddress });Safely transfer voucher (checks if recipient can receive NFTs).
Example:
await contract.methods.safeTransferFrom(
userAddress,
"0xRecipient...",
1
).send({ from: userAddress });Approve another address to transfer your voucher.
Example:
await contract.methods.approve("0xSpender...", 1).send({
from: userAddress
});Approve/revoke operator to manage all your vouchers.
Example:
await contract.methods.setApprovalForAll("0xOperator...", true).send({
from: userAddress
});Update price for a denomination.
Example:
await contract.methods.updatePrice(50, web3.utils.toWei("600", "ether")).send({
from: ownerAddress
});Withdraw all contract balance to owner.
Example:
await contract.methods.withdraw().send({ from: ownerAddress });Withdraw specific amount to address.
Example:
await contract.methods.withdrawTo(
"0xRecipient...",
web3.utils.toWei("1000", "ether")
).send({ from: ownerAddress });Transfer contract ownership.
Example:
await contract.methods.transferOwnership("0xNewOwner...").send({
from: ownerAddress
});{
"name": "Euro Voucher - 50€",
"description": "A 50 Euro voucher NFT on Monad blockchain. Purchase Date: 1/20/2026. Status: Active",
"image": "https://files.catbox.moe/4jezdg.jpeg",
"attributes": [
{
"trait_type": "Euro Value",
"value": 50
},
{
"trait_type": "Price Paid (MON)",
"value": 500
},
{
"trait_type": "Status",
"value": "Active"
},
{
"trait_type": "Purchase Date",
"value": "2026-01-20"
},
{
"trait_type": "Voucher ID",
"value": "VOC-1737380000-XYZ123"
}
]
}| Denomination | Preview | Image URL |
|---|---|---|
| 5€ | ![]() |
https://files.catbox.moe/mszp1d.jpeg |
| 10€ | ![]() |
https://files.catbox.moe/otcljk.jpeg |
| 20€ | ![]() |
https://files.catbox.moe/c11h9p.jpeg |
| 50€ | ![]() |
https://files.catbox.moe/4jezdg.jpeg |
| 100€ | ![]() |
https://files.catbox.moe/qlf6vq.jpeg |
| 500€ | ![]() |
https://files.catbox.moe/ir84ab.jpeg |
The contract emits these events for tracking:
event VoucherPurchased(
uint256 indexed tokenId,
address indexed buyer,
uint256 euroValue,
uint256 pricePaid,
string voucherId,
uint256 timestamp
);event VoucherRedeemed(
uint256 indexed tokenId,
address indexed redeemer,
uint256 euroValue,
uint256 timestamp
);event VoucherTransferred(
uint256 indexed tokenId,
address indexed from,
address indexed to,
uint256 timestamp
);event PriceUpdated(
uint256 euroValue,
uint256 oldPrice,
uint256 newPrice
);- HTML5
- JavaScript (ES6+)
- Tailwind CSS
- Web3.js v1.10.4
- JetBrains Mono Font
- Solidity ^0.8.20
- OpenZeppelin Contracts
- ERC-721 Standard
- Ownable Pattern
- Node.js
- Express.js
- CORS enabled
- Vercel (Frontend & API)
- Monad Blockchain (Smart Contract)
- MetaMask
- Remix IDE
- Monad Explorer
- ✅ Reentrancy protection
- ✅ Owner-only admin functions
- ✅ Duplicate voucher ID prevention
- ✅ Valid denomination checking
- ✅ Ownership verification
- ✅ Safe transfer checks
- ✅ Event emission for tracking
- Add voucher expiration dates
- Implement bulk purchase discounts
- Create voucher marketplace
- Add voucher gifting feature
- Mobile app integration
- Multi-chain support
- Voucher redemption portal
- Analytics dashboard
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Project Maintainer: Impera
const VAULT_ADDRESS = 0xE00454506f50ac31A0b87324513e28f77Db2a8F9
const SWAP_ROUTER_ADDRESS = 0x334cf8898EecCC0B98420E6910A3ae83A00b32e0
Contract Address: 0xa4d064E4ac881234961C076d314Abf9ac8d4E4BB
Frontend: https://euro-voucher-frontend.vercel.app
Metadata API: https://euro-voucher-metadata.vercel.app https://euro-voucher-nft.gitbook.io/euro-voucher-nft-docs/
- OpenZeppelin for secure smart contract libraries
- Monad blockchain for fast, low-cost transactions
- Vercel for reliable hosting
- MetaMask for wallet integration
- European Central Bank for euro banknote designs
This is an experimental project. Always do your own research before interacting with smart contracts. The developers are not responsible for any losses incurred through the use of this system.
Built with ❤️ on Monad Blockchain 🚀





