A smart contract for a mini-app that allows users to "mine" the DIAMANTE token. It's designed to create utility for
the ORO token by allowing users to spend it to initiate a mining session. In return, users receive DIAMANTE, a
fixed-supply token, with the reward amount determined by a pseudo-random mechanism based on network participation.
The contract includes a social referral feature, World ID integration for Sybil resistance, and is built using the UUPS upgradeable proxy pattern to allow for future logic updates.
The contract facilitates a simple mining game loop:
- Start Mining: A user spends
OROand provides a World ID proof to begin mining. - Remind a Friend: When starting mining, the user can nominate another user to "remind." If the reminded user also starts a mining session within the mining interval, the original user receives a bonus.
- Finish Mining: After the mining interval has passed, the user can call the
finishMiningfunction to claim theirDIAMANTEreward. - Reward Calculation:
- Base Reward: A base reward is calculated with a degree of unpredictability but not random.
- Referral Bonus: If the user's reminded friend successfully starts a mining session, a percentage-based bonus is added to the base reward.
- UUPS Upgradeable: Utilizes the ERC1967 UUPS proxy pattern for seamless logic upgrades.
- World ID Integration: Ensures that each person can only mine once per day, preventing Sybil attacks.
- Configurable Parameters: Contract parameters such as mining fee, reward amounts, and referral bonus percentages are configurable by the owner.
- Mining System: Users can mine DIAMANTE tokens by paying fees in ORO tokens
- Referral System: Users can refer friends and earn bonuses when their referred friends start mining
- Dynamic Rewards: Reward levels based on the number of active miners
- Flexible Referral Data: Support for encoded call data to enable future features like multiple friend referrals
startMining(root, nullifierHash, proof, userToRemind): Initiates a mining session for themsg.sender. Requires a valid World ID proof and transfersminingFeeInOrofrom the user.finishMining(): Allows a user to claim their rewards after theminingIntervalhas passed. Calculates the final reward (including any referral bonus) and transfers theDIAMANTEtokens.
This project uses Foundry.
npm installforge buildforge testTo view logs, add the -vvv flag:
forge test -vvvThe deployment script script/DeployUpgradeable.s.sol handles the deployment of the implementation contract and the
ERC1967 proxy.
To deploy to a local Anvil node:
-
Start a local node:
anvil -
Run the deployment script:
forge script script/DeployUpgradeable.s.sol --rpc-url localhost --broadcast
For instructions on how to deploy to a testnet or mainnet, check out the Solidity Scripting tutorial.
Get a gas report:
forge test --gas-reportnpm run lint- foundry-rs/forge-template
- abigger87/femplate
- cleanunicorn/ethereum-smartcontract-template
- FrankieIsLost/forge-template
This project is licensed under MIT.
The contract now supports encoded call data for referral addresses, providing flexibility for future features without requiring ABI changes.
// To refer a single friend
address[] memory referralAddresses = new address[](1);
referralAddresses[0] = friendAddress;
bytes memory referralData = abi.encode(referralAddresses);
diamanteMine.startMining(root, nullifier, proof, referralData, amount, permit);// For no referral, pass empty array
address[] memory referralAddresses = new address[](0);
bytes memory referralData = abi.encode(referralAddresses);
// Or simply pass empty bytes
bytes memory referralData = "";
diamanteMine.startMining(root, nullifier, proof, referralData, amount, permit);// Future support for multiple referrals
address[] memory referralAddresses = new address[](3);
referralAddresses[0] = friend1;
referralAddresses[1] = friend2;
referralAddresses[2] = friend3;
bytes memory referralData = abi.encode(referralAddresses);
// Currently uses only the first address, but the contract can be extended
// to support multiple referrals without changing the ABI
diamanteMine.startMining(root, nullifier, proof, referralData, amount, permit);The main function for starting mining:
function startMining(
uint256 root,
uint256 nullifierHash,
uint256[8] calldata proof,
bytes calldata referralData, // ABI-encoded address array
uint256 amount,
Permit2 memory permit
) external;forge testThe contract implements:
- Upgradeable proxy pattern (UUPS)
- OpenZeppelin security patterns
- Permit2 for gasless token approvals
- World ID for sybil resistance
The contract uses a proxy pattern for upgradeability. Deploy the implementation contract and then create a proxy pointing to it with the appropriate initialization parameters.