Skip to content

Commit

Permalink
add json parse functions
Browse files Browse the repository at this point in the history
  • Loading branch information
waynehoover committed Oct 19, 2023
1 parent 859e6e4 commit 9fe6ae1
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 5 deletions.
33 changes: 28 additions & 5 deletions contracts/QuestFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import {IERC1155} from "openzeppelin-contracts/token/ERC1155/IERC1155.sol";
import {IQuestOwnable} from "./interfaces/IQuestOwnable.sol";
import {IQuest1155Ownable} from "./interfaces/IQuest1155Ownable.sol";

import "forge-std/console.sol";


/// @title QuestFactory
/// @author RabbitHole.gg
/// @dev This contract is used to create quests and handle claims
Expand All @@ -31,7 +34,7 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto
using LibClone for address;
using LibString for string;
using LibString for uint256;
using JSONParserLib for string;
using JSONParserLib for *; // for JSONParserLib.Item and string

/*//////////////////////////////////////////////////////////////
STORAGE
Expand Down Expand Up @@ -311,11 +314,12 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto
/// @param signature_ The signature of the hash
/// @param jsonData_ The extra data for the quest
function claim(bytes32 hash_, bytes memory signature_, string memory jsonData_) external payable {
JSONParserLib.Item memory item;
item = jsonData_.parse();
JSONParserLib.Item memory item = jsonData_.parse();

address ref_ = address(bytes20(bytes(item.at('"ref"').value())));
string memory questId_ = item.at('"questId"').value();
string memory refString = item.at('"ref"').value().decodeString();
address ref_ = stringToAddress(refString);
string memory questId_ = item.at('"questId"').value().decodeString();
console.log("ref_", ref_);

if (quests[questId_].questType.eq("erc1155")) {
claim1155RewardsRef(ClaimData(questId_, hash_, signature_, ref_, 0, jsonData_));
Expand All @@ -324,6 +328,25 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto
}
}

// todo put in a library contract
function stringToAddress(string memory _a) public pure returns (address) {
bytes memory tmp = bytes(_a);
uint160 iaddr = 0;
uint160 b1;
uint160 b2;
for (uint i = 2; i < 2+2*20; i += 2) {
iaddr *= 256;
b1 = uint160(uint8(tmp[i]));
b2 = uint160(uint8(tmp[i+1]));
if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
iaddr += (b1*16+b2);
}
return address(iaddr);
}

/// @dev universal claim function for all quest types
/// @param questId_ The id of the quest
/// @param hash_ The hash of the message
Expand Down
40 changes: 40 additions & 0 deletions test/QuestFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import {Quest} from "contracts/Quest.sol";
import {Quest1155} from "contracts/Quest1155.sol";
import {SablierV2LockupLinearMock as SablierMock} from "./mocks/SablierV2LockupLinearMock.sol";
import {LibClone} from "solady/utils/LibClone.sol";
import {LibString} from "solady/utils/LibString.sol";
import {Errors} from "./helpers/Errors.sol";
import {Events} from "./helpers/Events.sol";
import {TestUtils} from "./helpers/TestUtils.sol";

contract TestQuestFactory is Test, Errors, Events, TestUtils {
using LibClone for address;
using LibString for address;

QuestFactory questFactory;
SampleERC1155 sampleERC1155;
Expand Down Expand Up @@ -347,6 +349,44 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils {
assertEq(referrer.balance, MINT_FEE / 3, "referrer mint fee");
}

function test_claim_with_jsonData() public{
vm.startPrank(owner);
questFactory.setRewardAllowlistAddress(address(sampleERC20), true);

vm.startPrank(questCreator);
sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(TOTAL_PARTICIPANTS, REWARD_AMOUNT, QUEST_FEE));
questFactory.createQuestAndQueue(
address(sampleERC20),
END_TIME,
START_TIME,
TOTAL_PARTICIPANTS,
REWARD_AMOUNT,
"questId2",
"actionSpec",
0
);

uint256 questCreatorBeforeBalance = questCreator.balance;
vm.warp(START_TIME + 1);

string memory referrerString = referrer.toHexString();
string memory json = string(abi.encodePacked('{"ref": "', referrerString, '", "questId": "questId2"}'));

bytes32 msgHash = keccak256(abi.encodePacked(participant, "questId2", referrer, json));
bytes memory signature = signHash(msgHash, claimSignerPrivateKey);

vm.startPrank(participant);
questFactory.claim{value: MINT_FEE}(msgHash, signature, json);

// erc20 reward
assertEq(sampleERC20.balanceOf(participant), REWARD_AMOUNT, "particpiant erc20 balance");

// claim fee rewards
assertEq(questCreator.balance - questCreatorBeforeBalance, MINT_FEE / 3, "questCreator mint fee");
assertEq(protocolFeeRecipient.balance, MINT_FEE / 3, "protocolFeeRecipient mint fee");
assertEq(referrer.balance, MINT_FEE / 3, "referrer mint fee");
}

function test_claim_with_claimRewards_without_referrer() public{
vm.startPrank(owner);
questFactory.setRewardAllowlistAddress(address(sampleERC20), true);
Expand Down

0 comments on commit 9fe6ae1

Please sign in to comment.