Smart Donations is an Ethereum smart contract for investing your donations, written in Solidity.
Smart Donations is a blockchain solution to invest your donations. Instead of directly donating to a charity, this contract allows you to invest your tokens and donate your interests generated through time. This gives charities a periodic income that lets them plan their activities with anticipation. And in the long term, the interests from your donations will surpass the original invested amount.
The basic idea is that you transfer your tokens to the contract, so that they are added to an investment pool. The investment pool will mint the equivalent token (cToken) in the Compound Protocol. Each cToken is assigned an interest rate and risk model, allowing you to generate interests just by holding cTokens. Compound is an algorithmic, autonomous interest rate protocol on blockchain for supplying or borrowing assets. More info here
You can check your interests generated and donate them whenever you want. Keep in mind that the amount you invest can't be donated or withdrawn, as it acts as the base of your interests generated. You can always invest more tokens to the investment pool, to increase the revenue. The contract keeps track of your total investment tokens and your interests of each token.
When you donate, you select the donees from a curated list of trusted charities. This list is mantained by the owner of the contract, but it could be upgraded with a governance token to allow the donors to manage the list of donees.
Entry point to the contracts, acting as controller. It allows donors to invest ERC20 tokens and donate the interests generated by each of them to the trusted donees. This contract needs to be approved by the ERC20 contract with the desired amount before investing. Accounts can also check their interests generated, the total amount invested, the available tokens to invest and the trusted donees list.
Manager of the trusted donees. Currently executed by an owner, who can add, enable and disable donees. In the future, it could be upgraded to a DAO with a governance token to manage donees.
This contract manages the donor's investments. It keeps track of the cToken balance of each donor for every token that they invest. InvestmentPool connects with cToken contracts of the Compound Protocol to invest, and creates an abstraction of this integration. This avoid external users to convert cToken to token just to know their real underlying balance or how much of the balance is interests generated vs original investment. InvestmentPool keeps track of every conversion to ensure that external users only see the underlying token (DAI, USDC...).
Compound Tokens (cToken) are self-contained borrowing and lending contracts. Each cToken is assigned an interest rate and risk model, and allows accounts to mint (supply capital), redeem (withdraw capital), borrow and repay a borrow. Each cToken is an ERC20 compliant token where balances represent ownership of the market.
- OpenZeppelin Ownable: Contract module which provides a basic access control mechanism, where there is an account (an owner) that can be granted exclusive access to specific functions.
- OpenZeppelin SafeERC20: Wrappers around ERC20 operations that throw on failure. Used for non conventional tokens like USDT.
- Download & Install Node.js and the npm package manager. If you encounter any problems, you can also use this GitHub Gist to install Node.js.
- Create an Alchemy account to connect to an archive node. This is used on Hardhat Network to fork mainnet and use Compound Protocol's smart contracts. Optionally, you can also use any other provider of Ethereum archive node.
To run the project, pull the repository and install its dependencies.
git clone https://github.com/javierpozzi/smart-donations.git
cd smart-donations
npm install
Rename file .env.example
to .env
on the root of the project.
Get your Alchemy key (or other provider Ethereum mainnet url) and paste it on FORKING_URL
variable inside .env
file:
FORKING_URL=https://eth-mainnet.alchemyapi.io/v2/<YOUR ALCHEMY KEY>
You can run the tests to verify that the installation was successful:
npm test
Depending of your archive node provider, some tests may timeout or take a long time the first time you run them. That's because the request to the provider doesn't complete on time. If that happens to you, just run the command again. Every time data is fetched from mainnet, Hardhat Network caches it on disk to speed up future access.
You can directly simulate a predefined scenario with:
npm run simulation
This will create an indepent instance of Hardhat Network, deploy the contracts and run the tasks to simulate an scenario where an address is seeded with tokens, invest them and then donate the interests to donees.
Alternatively, you can make your own simulations with a local network. To spin up an in-memory instance of the Hardhat Network, run:
npx hardhat node
On another console, deploy the contracts to the network:
npm run deploy-local
After this, you will have an HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
with the deployed contracts and a list of available accounts to use. You can run Tasks to the local server to simulate different scenarios.
Seed an address with 100000 of each token (DAI, USDC or USDT):
npx hardhat seedAddress --address YOUR_ADDRESS --network localhost
Invest a token:
npx hardhat invest --contract SMART_DONATION_ADDRESS --address YOUR_ADDRESS --token YOUR_TOKEN --amountnodecimals YOUR_AMOUNT --network localhost
Notes:
-
Available tokens: DAI, USDC and USDT.
-
Your SmartDonation address can be found on the logs when you deployed the contract.
-
amountnodecimals
parameter doesn't consider token's decimals. So if you want to invest 1000 DAI for example, you don't need to add 18 extra zeros for the decimals.
Check your invested amounts:
npx hardhat investedamount --contract SMART_DONATION_ADDRESS --address YOUR_ADDRESS --network localhost
Check your interests generated:
npx hardhat interests --contract SMART_DONATION_ADDRESS --address YOUR_ADDRESS --network localhost
Donate interests generated to predefined donees:
npx hardhat donate --contract SMART_DONATION_ADDRESS --address YOUR_ADDRESS --network localhost
The SmartDonation contract acts as the controller and should be the only entry point as a donor. The following functions are available to interact with the contract:
// Before investing a token, you should approve SmartDonation contract from the token's contract.
function investToken(bytes32 symbol, uint256 amount) external;
// The sum of the percentage of all donatedDonees should be 100.
function donateTokensGeneratedInterests(DonatedDoneeDTO[] donatedDoneeDTOs) external;
struct DonatedDoneeDTO {
address doneeAddress;
uint8 percentage;
}
function getTokenGeneratedInterests(bytes32 symbol) external view returns (uint256);
function getTokenInvestedAmount(bytes32 symbol) external view returns (uint256);
function getInvertibleTokens() external view returns (bytes32[] memory);
function getTrustedDonees() external view returns (address[] memory);
The TrustedDoneesManager is managed by an owner account. The following functions are available to interact with the contract:
function addDonee(bytes32 name, address addr) external;
function disableDonee(address _addr) external;
function enableDonee(address _addr) external;
function isDoneeEnabled(address _addr) external view returns (bool);
function getDonees() external view returns (address[] memory);
If you want to check gas usage run:
npm run gas-report
This software uses the following open source projects: