文件 1 的 2:Cloudwork.sol
pragma solidity ^0.8.7;
import "./Token.sol";
contract Cloudwork is Ownable {
mapping(address => bool) public allowedCoins;
uint256 public totalPaid;
uint256 public totalWithdrawn;
address public tokenAddressForDiscount;
uint256 public discountPercentage = 10;
uint256 public constant PERCENTAGE_DIVIDER = 1000;
uint256 public tokenHoldingForDiscount = 5000 ether;
uint256 public currentPaymentId;
mapping(address => uint256) public totalPaidPerCoin;
struct Payment {
uint256 id;
address sender;
address coin;
uint256 amount;
uint256 dicount;
uint256 amountAfterDiscount;
string message;
}
mapping(uint256 => Payment) public payments;
event PaymentReceived(
uint256 id,
address sender,
address coin,
uint256 amount,
string message
);
constructor(address[] memory coins, address _discountToken) Ownable() {
allowedCoins[address(0)] = true;
for (uint256 i = 0; i < coins.length; i++) {
allowedCoins[coins[i]] = true;
}
tokenAddressForDiscount = _discountToken;
}
function setDiscountToken(address tokenAddress) external onlyOwner {
tokenAddressForDiscount = tokenAddress;
}
function setDiscountPercentage(uint256 percentage) external onlyOwner {
discountPercentage = percentage;
}
function setTokenHoldingForDiscount(uint256 amount) external onlyOwner {
tokenHoldingForDiscount = amount;
}
function addAllowedCoin(address coin) external onlyOwner {
allowedCoins[coin] = true;
}
function removeAllowedCoin(address coin) external onlyOwner {
allowedCoins[coin] = false;
}
function pay(
address coin,
uint256 amount,
string calldata message
) external payable {
require(allowedCoins[coin], "Coin not allowed");
uint256 finalAmount = amount;
uint256 discount = 0;
if (tokenAddressForDiscount != address(0)) {
uint256 tokenBalance = ERC20(tokenAddressForDiscount).balanceOf(
msg.sender
);
if (tokenBalance >= tokenHoldingForDiscount) {
discount = (amount * discountPercentage) / PERCENTAGE_DIVIDER;
finalAmount -= discount;
}
}
if (coin == address(0)) {
require(msg.value == finalAmount, "Invalid amount");
} else {
ERC20(coin).transferFrom(msg.sender, address(this), finalAmount);
}
totalPaid += finalAmount;
totalPaidPerCoin[coin] += finalAmount;
currentPaymentId++;
uint256 id = currentPaymentId;
payments[id] = Payment(
id,
msg.sender,
coin,
amount,
discount,
finalAmount,
message
);
emit PaymentReceived(id, msg.sender, coin, amount, message);
}
fallback() external payable {}
receive() external payable {}
function withdraw(address coin, uint256 amount) external onlyOwner {
if (coin == address(0)) {
payable(owner).transfer(amount);
} else {
ERC20(coin).transfer(owner, amount);
}
}
}
文件 2 的 2:Token.sol
pragma solidity ^0.8.7;
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) public onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
abstract contract ERC20Basic {
uint public _totalSupply;
function totalSupply() public virtual returns (uint);
function balanceOf(address who) public virtual returns (uint);
function transfer(address to, uint value) public virtual;
event Transfer(address indexed from, address indexed to, uint value);
}
abstract contract ERC20 is ERC20Basic {
function allowance(
address owner,
address spender
) public virtual returns (uint);
function transferFrom(address from, address to, uint value) public virtual;
function approve(address spender, uint value) public virtual;
event Approval(address indexed owner, address indexed spender, uint value);
}
{
"compilationTarget": {
"contracts/Cloudwork.sol": "Cloudwork"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address[]","name":"coins","type":"address[]"},{"internalType":"address","name":"_discountToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"coin","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"PaymentReceived","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"PERCENTAGE_DIVIDER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"coin","type":"address"}],"name":"addAllowedCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedCoins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPaymentId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"discountPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"coin","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"message","type":"string"}],"name":"pay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"payments","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"coin","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"dicount","type":"uint256"},{"internalType":"uint256","name":"amountAfterDiscount","type":"uint256"},{"internalType":"string","name":"message","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"coin","type":"address"}],"name":"removeAllowedCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"setDiscountPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"setDiscountToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setTokenHoldingForDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenAddressForDiscount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenHoldingForDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalPaidPerCoin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWithdrawn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"coin","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]