Skip to content

Commit

Permalink
adding corrections
Browse files Browse the repository at this point in the history
:wq

:
  • Loading branch information
faytey committed Jul 3, 2024
1 parent 5080439 commit ac026c7
Show file tree
Hide file tree
Showing 8 changed files with 9,849 additions and 4,437 deletions.
16 changes: 16 additions & 0 deletions packages/contracts/src/MockResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./PlayerHandle.sol";

contract MockENSResolver is IENSResolver {
mapping(bytes32 => string) public names;

function setName(bytes32 node, string memory name) public {
names[node] = name;
}

function name(bytes32 node) external view override returns (string memory) {
return names[node];
}
}
106 changes: 106 additions & 0 deletions packages/contracts/src/PlayerHandle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

interface IENSResolver {
function name(bytes32 node) external view returns (string memory);
}

error InvalidHandle();
error HandleAlreadyTaken();
error PlayerNotEligible();

contract PlayerHandle is Ownable {
using Strings for uint256;

IENSResolver public ensResolver;
mapping(address => string) private handles;
mapping(string => address) private handleOwners;
mapping(address => bool) private useEns;

event HandleRegistered(address indexed player, string handle);
event HandleChanged(address indexed player, string newHandle);
event UseEnsSet(address indexed player, bool useEns);

constructor(address _ensResolver) {
ensResolver = IENSResolver(_ensResolver);
}

function registerHandle(string memory handle) external {
if (!checkHandleValidity(handle)) {
revert InvalidHandle();
}
if (handleOwners[handle] != address(0)) {
revert HandleAlreadyTaken();
}
if (!checkPlayerEligibility(msg.sender)) {
revert PlayerNotEligible();
}

if (bytes(handles[msg.sender]).length > 0) {
handleOwners[handles[msg.sender]] = address(0);
}

handles[msg.sender] = handle;
handleOwners[handle] = msg.sender;

emit HandleRegistered(msg.sender, handle);
}

function changeHandle(string memory newHandle) external {
if (!checkHandleValidity(newHandle)) {
revert InvalidHandle();
}

if (handleOwners[newHandle] != address(0)) {
revert HandleAlreadyTaken();
}

string memory oldHandle = handles[msg.sender];
handles[msg.sender] = newHandle;
handleOwners[newHandle] = msg.sender;
handleOwners[oldHandle] = address(0);

emit HandleChanged(msg.sender, newHandle);
}

function setUseEns(bool _useEns) external {
useEns[msg.sender] = _useEns;
emit UseEnsSet(msg.sender, _useEns);
}

function getPlayerHandle(address player) external view returns (string memory) {
if (useEns[player]) {
bytes32 node = keccak256(abi.encodePacked(addressToBytes32(player)));
string memory ensName = ensResolver.name(node);
if (bytes(ensName).length > 0) {
return ensName;
}
}
return handles[player];
}

function checkHandleValidity(string memory handle) public pure returns (bool) {
bytes memory b = bytes(handle);
if (b.length < 5 || b.length > 15) {
return false;
}
for (uint256 i; i < b.length; i++) {
bytes1 char = b[i];
if (!(char >= 0x30 && char <= 0x39) && !(char >= 0x41 && char <= 0x5A) && !(char >= 0x61 && char <= 0x7A)) {
return false;
}
}
return true;
}

function checkPlayerEligibility(address player) public pure returns (bool) {
return true; // Placeholder function; implement eligibility logic as needed
}

function addressToBytes32(address addr) private pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
}
8 changes: 8 additions & 0 deletions packages/contracts/src/deploy/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {InventoryCardsCollection} from "../InventoryCardsCollection.sol";
import {Groth16Verifier as DrawVerifier} from "../verifiers/DrawVerifier.sol";
import {Groth16Verifier as DrawHandVerifier} from "../verifiers/DrawHandVerifier.sol";
import {Groth16Verifier as PlayVerifier} from "../verifiers/PlayVerifier.sol";
import {MockENSResolver} from "../MockResolver.sol";
import {PlayerHandle} from "../PlayerHandle.sol";

import {Script, console2} from "forge-std/Script.sol";
// import {Multicall3} from "multicall/Multicall3.sol";
Expand All @@ -24,6 +26,8 @@ contract Deploy is Script {
DrawHandVerifier public drawHandVerifier;
Game public game;
DeckAirdrop public airdrop;
MockENSResolver public mockEnsResolver;
PlayerHandle public playerHandle;

bool private doLog = true;

Expand Down Expand Up @@ -51,6 +55,8 @@ contract Deploy is Script {
bool noRandom = vm.envOr("NO_RANDOM", false);
game = new Game(inventory, drawVerifier, playVerifier, drawHandVerifier, checkProofs, noRandom);
airdrop = new DeckAirdrop(inventory);
mockEnsResolver = new MockENSResolver();
playerHandle = new PlayerHandle(address(mockEnsResolver));

// initialize
cardsCollection.setInventory(inventory);
Expand All @@ -63,6 +69,8 @@ contract Deploy is Script {
log("InventoryCardsCollection address", address(inventoryCardsCollection));
log("Game address", address(game));
log("DeckAirdrop address", address(airdrop));
log("MockENSResolver address", address(mockEnsResolver));
log("PlayerHandle address", address(playerHandle));

vm.stopBroadcast();

Expand Down
78 changes: 78 additions & 0 deletions packages/contracts/src/test/PlayerHandle.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "../PlayerHandle.sol";
import {MockENSResolver} from "../MockResolver.sol";

// running tests for PlayerHandle and MockENSResolver
contract PlayerHandleTest is Test {
PlayerHandle public playerHandle;
MockENSResolver public mockENSResolver;

address public alice = address(0x1);
address public bob = address(0x2);

function setUp() public {
mockENSResolver = new MockENSResolver();
playerHandle = new PlayerHandle(address(mockENSResolver));
}

function testRegisterHandle() public {
vm.prank(alice);
playerHandle.registerHandle("AliceHandle");

assertEq(playerHandle.getPlayerHandle(alice), "AliceHandle");
}

function testRegisterInvalidHandle() public {
vm.prank(alice);
vm.expectRevert(abi.encodeWithSignature("InvalidHandle()"));
playerHandle.registerHandle("a");
}

function testHandleAlreadyTaken() public {
vm.prank(alice);
playerHandle.registerHandle("AliceHandle");

vm.prank(bob);
vm.expectRevert(abi.encodeWithSignature("HandleAlreadyTaken()"));
playerHandle.registerHandle("AliceHandle");
}

function testChangeHandle() public {
vm.prank(alice);
playerHandle.registerHandle("AliceHandle");

vm.prank(alice);
playerHandle.changeHandle("NewAliceHandle");

assertEq(playerHandle.getPlayerHandle(alice), "NewAliceHandle");
}

function testSetUseEns() public {
bytes32 node = keccak256(abi.encodePacked(addressToBytes32(alice)));
mockENSResolver.setName(node, "alice.eth");

vm.prank(alice);
playerHandle.setUseEns(true);

assertEq(playerHandle.getPlayerHandle(alice), "alice.eth");
}

function testUnsetUseEns() public {
bytes32 node = keccak256(abi.encodePacked(addressToBytes32(alice)));
mockENSResolver.setName(node, "alice.eth");

vm.prank(alice);
playerHandle.registerHandle("AliceHandle");
playerHandle.setUseEns(true);
playerHandle.setUseEns(false);

assertEq(playerHandle.getPlayerHandle(alice), "AliceHandle");
}

function addressToBytes32(address addr) private pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
}
2 changes: 2 additions & 0 deletions packages/webapp/src/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface Deployment {
Game: Address
DeckAirdrop: Address
Multicall3: Address
PlayerHandle: Address
MockENSResolver: Address
}

// NOTE: This silly `default` affair is required for running the e2e tests which cause
Expand Down
33 changes: 33 additions & 0 deletions packages/webapp/src/hooks/useOfflineCheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect, useState } from "react"

import { toast } from "sonner"

function useOfflineCheck() {
const [isOnline, setIsOnline] = useState(true)

useEffect(() => {
const handleOnline = () => setIsOnline(true)
const handleOffline = () => setIsOnline(false)

window.addEventListener("online", handleOnline)
window.addEventListener("offline", handleOffline)

return () => {
window.removeEventListener("online", handleOnline)
window.removeEventListener("offline", handleOffline)
}
}, [])

useEffect(() => {
if (!isOnline) {
toast.error("App is offline. Please check your internet connection.", {
dismissible: false,
duration: Infinity,
})
} else {
toast.dismiss()
}
}, [isOnline])
}

export default useOfflineCheck
2 changes: 2 additions & 0 deletions packages/webapp/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import jotaiDebug from "src/components/lib/jotaiDebug"
import { GlobalErrorModal } from "src/components/modals/globalErrorModal"
import { Toaster } from "src/components/ui/sonner"
import { useIsHydrated } from "src/hooks/useIsHydrated"
import useOfflineCheck from "src/hooks/useOfflineCheck"
import { useErrorConfig } from "src/store/hooks"

import "src/styles/globals.css"
Expand All @@ -33,6 +34,7 @@ export type FablePage = NextPage<{ isHydrated: boolean }>
// =================================================================================================

const MyApp: AppType = ({ Component, pageProps }) => {
useOfflineCheck()
return (
<>
<Head>
Expand Down
Loading

0 comments on commit ac026c7

Please sign in to comment.