Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add squeeze rewards #1

Merged
merged 4 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/hardhat/.prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
{
"files": "*.sol",
"options": {
"printWidth": 80,
"printWidth": 120,
"tabWidth": 4,
"useTabs": true,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": true,
"explicitTypes": "always"
Expand Down
167 changes: 167 additions & 0 deletions packages/hardhat/contracts/FrogCryptoSqueeze.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Poseidon.sol";
import "./Groth16Verifier.sol";

abstract contract PotionTokenContract {
function mint(address to, uint256 amount) public virtual;
}

contract FrogCryptoSqueeze is Groth16Verifier, Poseidon {
// The known hash of the FrogCrypto signer
uint256 constant FROGCRYPTO_SIGNER_HASH =
320469162396708332516033932244029190181315114284264408621970394677041964715;

// Mapping from frogId to squeeze timestamp
mapping(uint256 => uint256) public squeezeTimestamps;

PotionTokenContract public rarityTokenContract;
PotionTokenContract public temperamentTokenContract;
PotionTokenContract public jumpTokenContract;
PotionTokenContract public speedTokenContract;
PotionTokenContract public intelligenceTokenContract;
PotionTokenContract public beautyTokenContract;

struct ProofArgs {
uint256[2] _pA;
uint256[2][2] _pB;
uint256[2] _pC;
uint256[60] _pubSignals;
}

struct FrogAttributes {
uint256 beauty;
uint256 biome;
uint256 intelligence;
uint256 jump;
uint256 speed;
uint256 rarity;
uint256 owner;
uint256 temperament;
uint256 frogId;
}

event Squeeze(
uint256 indexed frogId,
address indexed owner,
uint256 rarityReward,
uint256 jummpReward,
uint256 speedReward,
uint256 intelligenceReward,
uint256 beautyReward
);

modifier verifiedProof(ProofArgs calldata proof) {
require(this.verifyProof(proof._pA, proof._pB, proof._pC, proof._pubSignals), "Invalid proof");
_;
}

constructor(
address rarityTokenAddress,
address jumpTokenAddress,
address speedTokenAddress,
address intelligenceTokenAddress,
address beautyTokenAddress
) {
rarityTokenContract = PotionTokenContract(rarityTokenAddress);
jumpTokenContract = PotionTokenContract(jumpTokenAddress);
speedTokenContract = PotionTokenContract(speedTokenAddress);
intelligenceTokenContract = PotionTokenContract(intelligenceTokenAddress);
beautyTokenContract = PotionTokenContract(beautyTokenAddress);
}

function squeezeFrog(ProofArgs calldata proof, FrogAttributes calldata attributes, address owner) public {
// First verify the proof and attributes
require(verifyFrogAttributes(proof, attributes), "Invalid frog attributes");

// TODO: change cooldown period
require(
squeezeTimestamps[attributes.frogId] + 1 minutes < block.timestamp,
"Squeeze: Cooldown period is not over yet"
);

squeezeTimestamps[attributes.frogId] = block.timestamp;

bytes32 predictableRandom = keccak256(
abi.encodePacked(attributes.frogId, blockhash(block.number - 1), msg.sender, address(this))
);

uint8 temperamentMultiplier = 1;

// cool temperament gets a bonus (we can add another bonus later)
if (attributes.temperament == 6) {
temperamentMultiplier = 2;
}

uint256 rarityAmount = ((uint256(uint8(predictableRandom[0])) % 10) + 1) *
(attributes.rarity + 1) *
temperamentMultiplier;
uint256 jumpAmount = ((uint256(uint8(predictableRandom[2])) % 10) + 1) *
(attributes.jump + 1) *
temperamentMultiplier;
uint256 speedAmount = ((uint256(uint8(predictableRandom[3])) % 10) + 1) *
(attributes.speed + 1) *
temperamentMultiplier;
uint256 intelligenceAmount = ((uint256(uint8(predictableRandom[4])) % 10) + 1) *
(attributes.intelligence + 1) *
temperamentMultiplier;
uint256 beautyAmount = ((uint256(uint8(predictableRandom[5])) % 10) + 1) *
(attributes.beauty + 1) *
temperamentMultiplier;

rarityTokenContract.mint(owner, rarityAmount);
jumpTokenContract.mint(owner, jumpAmount);
speedTokenContract.mint(owner, speedAmount);
intelligenceTokenContract.mint(owner, intelligenceAmount);
beautyTokenContract.mint(owner, beautyAmount);

emit Squeeze(attributes.frogId, owner, rarityAmount, jumpAmount, speedAmount, intelligenceAmount, beautyAmount);
}

function verifyFrogAttributes(ProofArgs calldata proof, FrogAttributes calldata attrs) public view returns (bool) {
uint256[60] memory pubSignals = proof._pubSignals;

// Verify FrogCrypto signer
require(pubSignals[25] == FROGCRYPTO_SIGNER_HASH, "Invalid signer");

uint256[1] memory input;

// Verify beauty
input[0] = attrs.beauty;
require(this.hash(input) == pubSignals[0], "Invalid beauty value");

// Verify biome
input[0] = attrs.biome;
require(this.hash(input) == pubSignals[1], "Invalid biome value");

// verify frogId
input[0] = attrs.frogId;
require(this.hash(input) == pubSignals[3], "Invalid frogId value");

// Verify intelligence
input[0] = attrs.intelligence;
require(this.hash(input) == pubSignals[4], "Invalid intelligence value");

// Verify jump
input[0] = attrs.jump;
require(this.hash(input) == pubSignals[5], "Invalid jump value");

// Verify owner
input[0] = attrs.owner;
require(this.hash(input) == pubSignals[7], "Invalid owner value");

// Verify rarity
input[0] = attrs.rarity;
require(this.hash(input) == pubSignals[8], "Invalid rarity value");

// Verify speed
input[0] = attrs.speed;
require(this.hash(input) == pubSignals[9], "Invalid speed value");

input[0] = attrs.temperament;
require(this.hash(input) == pubSignals[10], "Invalid speed value");

return true;
}
}
39 changes: 39 additions & 0 deletions packages/hardhat/contracts/PotionToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

/**
* ERC20 potion token contract
*/
contract PotionToken is ERC20, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}

function decimals() public pure override returns (uint8) {
return 0;
}

function transferOwnership(address newOwner) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(!hasRole(DEFAULT_ADMIN_ROLE, newOwner), "Ownable: new owner already have admin role");

grantRole(DEFAULT_ADMIN_ROLE, newOwner);
renounceRole(DEFAULT_ADMIN_ROLE, msg.sender);
}

function grantMinterRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
grantRole(MINTER_ROLE, account);
}

function revokeMinterRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
revokeRole(MINTER_ROLE, account);
}

function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
}
147 changes: 0 additions & 147 deletions packages/hardhat/contracts/YourContract.sol

This file was deleted.

Loading
Loading