Skip to content

Commit

Permalink
Add squeeze rewards (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
damianmarti authored Nov 6, 2024
1 parent 249c528 commit d3ab6ff
Show file tree
Hide file tree
Showing 13 changed files with 3,241 additions and 511 deletions.
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

0 comments on commit d3ab6ff

Please sign in to comment.