pragma solidity ^0.8.0;
import "./CharityRegistry.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
error GivingThanks__CharityNotVerified();
error GivingThanks__FailedToSendEther();
contract GivingThanks is ERC721URIStorage {
CharityRegistry public registry;
uint256 public tokenCounter;
address public immutable i_owner;
constructor(address _registry) ERC721("DonationReceipt", "DRC") {
registry = CharityRegistry(_registry);
i_owner = msg.sender;
tokenCounter = 0;
}
function donate(address charity) public payable {
if (!registry.isVerified(charity)) revert GivingThanks__CharityNotVerified();
(bool sent, ) = charity.call{value: msg.value}("");
if (!sent) revert GivingThanks__FailedToSendEther();
_mint(msg.sender, tokenCounter);
string memory uri = _createTokenURI(
msg.sender,
block.timestamp,
msg.value
);
_setTokenURI(tokenCounter, uri);
tokenCounter += 1;
}
function _createTokenURI(
address donor,
uint256 date,
uint256 amount
) internal pure returns (string memory) {
string memory json = string(
abi.encodePacked(
'{"donor":"',
Strings.toHexString(uint160(donor), 20),
'","date":"',
Strings.toString(date),
'","amount":"',
Strings.toString(amount),
'"}'
)
);
string memory base64Json = Base64.encode(bytes(json));
return
string(
abi.encodePacked("data:application/json;base64,", base64Json)
);
}
function updateRegistry(address _registry) public {
registry = CharityRegistry(_registry);
}
}
pragma solidity ^0.8.0;
error CharityRegistry__OnlyAdminCanVerify();
error CharityRegistry__CharityNotRegistered();
error CharityRegistry__OnlyAdminCanChangeAdmin();
contract CharityRegistry {
address public immutable i_admin;
mapping(address => bool) public s_verifiedCharities;
mapping(address => bool) public s_registeredCharities;
constructor() {
i_admin = msg.sender;
}
function registerCharity(address charity) public {
s_registeredCharities[charity] = true;
}
function verifyCharity(address charity) public {
if (msg.sender != i_admin) revert CharityRegistry__OnlyAdminCanVerify();
if (!s_registeredCharities[charity]) revert CharityRegistry__CharityNotRegistered();
s_verifiedCharities[charity] = true;
}
function isVerified(address charity) public view returns (bool) {
return s_verifiedCharities[charity];
}
function changeAdmin(address newAdmin) public {
if (msg.sender != i_admin) revert CharityRegistry__OnlyAdminCanChangeAdmin();
i_admin = newAdmin;
}
}