Description:
Smart contract deployed on Ethereum with Oracle features.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
interface AggregatorV3Interface {
function latestRoundData() external view returns (
uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound
);
function decimals() external view returns (uint8);
}
contract SyntheticPrepaidCardSystem {
address public owner;
IERC20 public constant USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
IERC20 public constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
AggregatorV3Interface public ethUsdFeed;
AggregatorV3Interface public usdtUsdFeed;
AggregatorV3Interface public usdcUsdFeed;
struct PaymentCard {
string number;
string expiration;
uint16 securityCode;
string cardType;
string status;
uint256 ethBalance;
uint256 usdtBalance;
uint256 usdcBalance;
uint256 syntheticBalance; // synthetic token units
string paypalAccount;
}
PaymentCard[] public cards;
/* ---------- Events ---------- */
event CardCreated(uint256 indexed cardIndex, string cardType, string number);
event SpendExecuted(uint256 indexed cardIndex, string merchant, string asset, uint256 amount);
event PayPalLinkRequested(uint256 indexed cardIndex, string number, string cardType, string expiration, uint16 securityCode);
event PayPalLinkConfirmed(uint256 indexed cardIndex, string paypalAccount);
event Deposit(uint256 indexed cardIndex, string asset, uint256 amount);
event Withdraw(uint256 indexed cardIndex, string asset, uint256 amount);
event OracleUpdated(string asset, address feed);
event SwapExecuted(uint256 indexed cardIndex, string fromAsset, string toAsset, uint256 amountFrom, uint256 amountTo);
modifier onlyOwner() { require(msg.sender == owner, "Not authorized"); _; }
modifier validCardIndex(uint256 index) { require(index < cards.length, "Invalid card index"); _; }
constructor() { owner = msg.sender; }
/* ---------- Oracles ---------- */
function setEthUsdFeed(address feed) external onlyOwner { ethUsdFeed = AggregatorV3Interface(feed); emit OracleUpdated("ETH", feed); }
function setUsdtUsdFeed(address feed) external onlyOwner { usdtUsdFeed = AggregatorV3Interface(feed); emit OracleUpdated("USDT", feed); }
function setUsdcUsdFeed(address feed) external onlyOwner { usdcUsdFeed = AggregatorV3Interface(feed); emit OracleUpdated("USDC", feed); }
function _getLatestPrice(AggregatorV3Interface feed) internal view returns (uint256) {
require(address(feed) != address(0), "Oracle not set");
(, int256 price,,,) = feed.latestRoundData();
require(price > 0, "Invalid price");
uint8 dec = feed.decimals();
if (dec < 18) return uint256(price) * 10**(18 - dec);
else if (dec > 18) return uint256(price) / 10**(dec - 18);
else return uint256(price);
}
/* ---------- Utilities ---------- */
function uintToString(uint256 v) internal pure returns (string memory str) {
if (v == 0) return "0";
uint256 j = v; uint256 length; while (j != 0) { length++; j /= 10; }
bytes memory bstr = new bytes(length);
uint256 k = length; j = v;
while (j != 0) { bstr[--k] = bytes1(uint8(48 + j % 10)); j /= 10; }
str = string(bstr);
}
function generatePseudoRandom(uint seed, uint offset) internal view returns (uint256) {
return uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, seed, offset)));
}
function calculateLuhnCheckDigit(string memory base) internal pure returns (uint8) {
bytes memory digits = bytes(base);
uint256 sum = 0;
bool doubleDigit = true;
for (uint256 i = digits.length; i > 0; i--) {
uint8 d = uint8(digits[i - 1]) - 48;
if (doubleDigit) { d *= 2; if (d > 9) d -= 9; }
sum += d; doubleDigit = !doubleDigit;
}
return uint8((10 - (sum % 10)) % 10);
}
/* ---------- Card Generation ---------- */
function generateSyntheticVisa(uint seed) internal view returns (PaymentCard memory) {
string memory base = "4";
for (uint j = 0; j < 14; j++) { base = string(abi.encodePacked(base, uintToString(generatePseudoRandom(seed, j) % 10))); }
uint8 checkDigit = calculateLuhnCheckDigit(base);
string memory fullNumber = string(abi.encodePacked(base, uintToString(checkDigit)));
return PaymentCard(fullNumber,"12/2027",uint16(100 + (generatePseudoRandom(seed,99)%900)),"Visa","Active",0,0,0,0,"");
}
function generateSyntheticMasterCard(uint seed) internal view returns (PaymentCard memory) {
string memory base = "5";
base = string(abi.encodePacked(base, uintToString(1 + (generatePseudoRandom(seed,0)%5))));
for (uint j=0;j<13;j++){ base=string(abi.encodePacked(base,uintToString(generatePseudoRandom(seed,j+1)%10))); }
uint8 checkDigit = calculateLuhnCheckDigit(base);
string memory fullNumber = string(abi.encodePacked(base,uintToString(checkDigit)));
return PaymentCard(fullNumber,"12/2027",uint16(100+(generatePseudoRandom(seed,88)%900)),"MasterCard","Active",0,0,0,0,"");
}
function createVisaCard(uint seed) external onlyOwner { PaymentCard memory c=generateSyntheticVisa(seed); cards.push(c); emit CardCreated(cards.length-1,c.cardType,c.number); }
function createMasterCard(uint seed) external onlyOwner { PaymentCard memory c=generateSyntheticMasterCard(seed); cards.push(c); emit CardCreated(cards.length-1,c.cardType,c.number); }
/* ---------- Deposits ---------- */
function depositETH(uint256 cardIndex) external payable validCardIndex(cardIndex) { cards[cardIndex].ethBalance += msg.value; emit Deposit(cardIndex,"ETH",msg.value); }
function depositUSDT(uint256 cardIndex,uint256 amount) external validCardIndex(cardIndex) { require(USDT.transferFrom(msg.sender,address(this),amount),"USDT transfer failed"); cards[cardIndex].usdtBalance+=amount; emit Deposit(cardIndex,"USDT",amount);}
function depositUSDC(uint256 cardIndex,uint256 amount) external validCardIndex(cardIndex) { require(USDC.transferFrom(msg.sender,address(this),amount),"USDC transfer failed"); cards[cardIndex].usdcBalance+=amount; emit Deposit(cardIndex,"USDC",amount);}
/* ---------- Withdrawals ---------- */
function withdrawETH(uint256 cardIndex,uint256 amount) external onlyOwner validCardIndex(cardIndex){ require(cards[cardIndex].ethBalance>=amount,"Insufficient ETH"); cards[cardIndex].ethBalance-=amount; payable(owner).transfer(amount); emit Withdraw(cardIndex,"ETH",amount);}
function withdrawUSDT(uint256 cardIndex,uint256 amount) external onlyOwner validCardIndex(cardIndex){ require(cards[cardIndex].usdtBalance>=amount,"Insufficient USDT"); cards[cardIndex].usdtBalance-=amount; require(USDT.transfer(owner,amount),"USDT transfer failed"); emit Withdraw(cardIndex,"USDT",amount);}
function withdrawUSDC(uint256 cardIndex,uint256 amount) external onlyOwner validCardIndex(cardIndex){ require(cards[cardIndex].usdcBalance>=amount,"Insufficient USDC"); cards[cardIndex].usdcBalance-=amount; require(USDC.transfer(owner,amount),"USDC transfer failed"); emit Withdraw(cardIndex,"USDC",amount); }
/* ---------- Spend ---------- */
function spendFromCard(uint256 cardIndex,string calldata merchant,string calldata asset,uint256 amount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex];
if(keccak256(bytes(asset))==keccak256("ETH")){ require(c.ethBalance>=amount,"Insufficient ETH"); c.ethBalance-=amount;}
else if(keccak256(bytes(asset))==keccak256("USDT")){ require(c.usdtBalance>=amount,"Insufficient USDT"); c.usdtBalance-=amount;}
else if(keccak256(bytes(asset))==keccak256("USDC")){ require(c.usdcBalance>=amount,"Insufficient USDC"); c.usdcBalance-=amount;}
else if(keccak256(bytes(asset))==keccak256("SYNTH")){ require(c.syntheticBalance>=amount,"Insufficient SYNTH"); c.syntheticBalance-=amount;}
else{ revert("Unknown asset"); }
emit SpendExecuted(cardIndex,merchant,asset,amount);
}
/* ---------- Swaps ---------- */
function swapETHToUSDT(uint256 cardIndex,uint256 ethAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.ethBalance>=ethAmount,"Insufficient ETH");
uint256 ethPrice=_getLatestPrice(ethUsdFeed); uint256 usdtAmount=(ethAmount*ethPrice)/1e18/1e12;
c.ethBalance-=ethAmount; c.usdtBalance+=usdtAmount; emit SwapExecuted(cardIndex,"ETH","USDT",ethAmount,usdtAmount);
}
function swapETHToUSDC(uint256 cardIndex,uint256 ethAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.ethBalance>=ethAmount,"Insufficient ETH");
uint256 ethPrice=_getLatestPrice(ethUsdFeed); uint256 usdcAmount=(ethAmount*ethPrice)/1e18/1e12;
c.ethBalance-=ethAmount; c.usdcBalance+=usdcAmount; emit SwapExecuted(cardIndex,"ETH","USDC",ethAmount,usdcAmount);
}
function swapETHToSynth(uint256 cardIndex,uint256 ethAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.ethBalance>=ethAmount,"Insufficient ETH");
uint256 ethPrice=_getLatestPrice(ethUsdFeed); uint256 synthAmount=(ethAmount*ethPrice)/1e18;
c.ethBalance-=ethAmount; c.syntheticBalance+=synthAmount; emit SwapExecuted(cardIndex,"ETH","SYNTH",ethAmount,synthAmount);
}
function swapSynthToETH(uint256 cardIndex,uint256 synthAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.syntheticBalance>=synthAmount,"Insufficient SYNTH");
uint256 ethPrice=_getLatestPrice(ethUsdFeed); uint256 ethAmount=(synthAmount*1e18)/ethPrice;
c.syntheticBalance-=synthAmount; c.ethBalance+=ethAmount; emit SwapExecuted(cardIndex,"SYNTH","ETH",synthAmount,ethAmount);
}
function swapSynthToUSDT(uint256 cardIndex,uint256 synthAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.syntheticBalance>=synthAmount,"Insufficient SYNTH");
uint256 usdtPrice=_getLatestPrice(usdtUsdFeed); uint256 usdtAmount=(synthAmount*1e18)/usdtPrice;
c.syntheticBalance-=synthAmount; c.usdtBalance+=usdtAmount; emit SwapExecuted(cardIndex,"SYNTH","USDT",synthAmount,usdtAmount);
}
function swapSynthToUSDC(uint256 cardIndex,uint256 synthAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.syntheticBalance>=synthAmount,"Insufficient SYNTH");
uint256 usdcPrice=_getLatestPrice(usdcUsdFeed); uint256 usdcAmount=(synthAmount*1e18)/usdcPrice;
c.syntheticBalance-=synthAmount; c.usdcBalance+=usdcAmount; emit SwapExecuted(cardIndex,"SYNTH","USDC",synthAmount,usdcAmount);
}
/* ---------- Reverse Swaps ---------- */
function swapUSDTToSynth(uint256 cardIndex,uint256 usdtAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.usdtBalance>=usdtAmount,"Insufficient USDT");
uint256 usdtPrice=_getLatestPrice(usdtUsdFeed); uint256 synthAmount=(usdtAmount*1e18)/usdtPrice;
c.usdtBalance-=usdtAmount; c.syntheticBalance+=synthAmount; emit SwapExecuted(cardIndex,"USDT","SYNTH",usdtAmount,synthAmount);
}
function swapUSDCToSynth(uint256 cardIndex,uint256 usdcAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.usdcBalance>=usdcAmount,"Insufficient USDC");
uint256 usdcPrice=_getLatestPrice(usdcUsdFeed); uint256 synthAmount=(usdcAmount*1e18)/usdcPrice;
c.usdcBalance-=usdcAmount; c.syntheticBalance+=synthAmount; emit SwapExecuted(cardIndex,"USDC","SYNTH",usdcAmount,synthAmount);
}
function swapUSDTToETH(uint256 cardIndex,uint256 usdtAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.usdtBalance>=usdtAmount,"Insufficient USDT");
uint256 usdtPrice=_getLatestPrice(usdtUsdFeed); uint256 ethAmount=(usdtAmount*1e18)/usdtPrice;
c.usdtBalance-=usdtAmount; c.ethBalance+=ethAmount; emit SwapExecuted(cardIndex,"USDT","ETH",usdtAmount,ethAmount);
}
function swapUSDCToETH(uint256 cardIndex,uint256 usdcAmount) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex]; require(c.usdcBalance>=usdcAmount,"Insufficient USDC");
uint256 usdcPrice=_getLatestPrice(usdcUsdFeed); uint256 ethAmount=(usdcAmount*1e18)/usdcPrice;
c.usdcBalance-=usdcAmount; c.ethBalance+=ethAmount; emit SwapExecuted(cardIndex,"USDC","ETH",usdcAmount,ethAmount);
}
/* ---------- PayPal Linking ---------- */
function requestPayPalLink(uint256 cardIndex) external onlyOwner validCardIndex(cardIndex){
PaymentCard storage c=cards[cardIndex];
emit PayPalLinkRequested(cardIndex,c.number,c.cardType,c.expiration,c.securityCode);
}
function confirmPayPalLink(uint256 cardIndex,string calldata paypalAccount) external onlyOwner validCardIndex(cardIndex){
cards[cardIndex].paypalAccount = paypalAccount;
emit PayPalLinkConfirmed(cardIndex,paypalAccount);
}
/* ---------- Views ---------- */
function getCard(uint256 cardIndex) external view validCardIndex(cardIndex) returns (PaymentCard memory){ return cards[cardIndex]; }
function getAllCards() external view returns (PaymentCard[] memory){ return cards; }
function getContractBalance() external view returns(uint256){ return address(this).balance; }
receive() external payable {}
}
Submitted on: 2025-09-27 11:02:57
Comments
Log in to comment.
No comments yet.